Restore point
This commit is contained in:
Родитель
063765d99f
Коммит
61ffdbdb1a
|
@ -4,10 +4,23 @@ namespace Unity.Exceptions
|
|||
{
|
||||
public class InvalidRegistrationException : Exception
|
||||
{
|
||||
internal InvalidRegistrationException(Exception ex)
|
||||
: base(ex.Message, ex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal InvalidRegistrationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal InvalidRegistrationException(string message, object info)
|
||||
: base(message)
|
||||
{
|
||||
Data.Add(Guid.NewGuid(), info);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity.Exceptions;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public abstract class MethodBasePipeline<TMemberInfo> : MemberPipeline<TMemberInfo, object[]>
|
||||
where TMemberInfo : MethodBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
protected readonly UnityContainer Container;
|
||||
protected readonly ParametersProcessor Processor;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
protected MethodBasePipeline(Type attribute, UnityContainer container, ParametersProcessor? processor)
|
||||
: base(container)
|
||||
{
|
||||
Container = container;
|
||||
Markers = new[] { attribute };
|
||||
Processor = processor ?? new ParametersProcessor();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Markers
|
||||
|
||||
public void AddMarkers(IEnumerable<Type> attributes)
|
||||
{
|
||||
Markers = Markers.Concat(attributes).ToArray();
|
||||
}
|
||||
|
||||
public Type[] Markers { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Overrides
|
||||
|
||||
protected override Type MemberType(TMemberInfo info) => info.DeclaringType;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implementation
|
||||
|
||||
protected virtual IEnumerable<ResolveDelegate<PipelineContext>> ParameterResolvers(ParameterInfo[] parameters, object? injectors)
|
||||
{
|
||||
if (null != injectors && injectors is object[] resolvers && 0 != resolvers.Length)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
yield return Processor.ParameterResolver(parameters[i], resolvers[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
yield return Processor.ParameterResolver(parameters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<Expression> ParameterExpressions(ParameterExpression[] expressions, ParameterInfo[] parameters, object? injectors)
|
||||
{
|
||||
if (null != injectors && injectors is object[] resolvers && 0 != resolvers.Length)
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
yield return Processor.ParameterExpression(expressions[i], parameters[i], resolvers[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
yield return Processor.ParameterExpression(expressions[i], parameters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ParameterExpression ToVariable(ParameterInfo info)
|
||||
{
|
||||
if (info.ParameterType.IsByRef)
|
||||
throw new InvalidRegistrationException($"Invalid By Ref parameter '{info.Name}' ({info.ParameterType})", info);
|
||||
|
||||
return Expression.Variable(info.ParameterType, info.Name);
|
||||
}
|
||||
|
||||
protected bool CanResolve(ParameterInfo info)
|
||||
{
|
||||
foreach (var node in AttributeFactories)
|
||||
{
|
||||
if (null == node.Factory) continue;
|
||||
var attribute = info.GetCustomAttribute(node.Type);
|
||||
if (null == attribute) continue;
|
||||
|
||||
// If found match, use provided factory to create expression
|
||||
return Container.CanResolve(info.ParameterType, node.Name(attribute));
|
||||
}
|
||||
|
||||
return Container.CanResolve(info.ParameterType, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -52,15 +52,15 @@ namespace Unity
|
|||
typeof(string) == parameters[0].ParameterType;
|
||||
});
|
||||
|
||||
protected static readonly Expression NewGuid = Expression.Call(typeof(Guid).GetTypeInfo().GetDeclaredMethod(nameof(Guid.NewGuid)));
|
||||
protected static readonly Expression CallNewGuidExpr = Expression.Call(typeof(Guid).GetTypeInfo().GetDeclaredMethod(nameof(Guid.NewGuid)));
|
||||
|
||||
protected static readonly PropertyInfo DataProperty = typeof(Exception).GetTypeInfo().GetDeclaredProperty(nameof(Exception.Data));
|
||||
protected static readonly PropertyInfo DataPropertyInfo = typeof(Exception).GetTypeInfo().GetDeclaredProperty(nameof(Exception.Data));
|
||||
|
||||
protected static readonly MethodInfo AddMethod = typeof(IDictionary).GetTypeInfo().GetDeclaredMethod(nameof(IDictionary.Add));
|
||||
protected static readonly MethodInfo AddMethodInfo = typeof(IDictionary).GetTypeInfo().GetDeclaredMethod(nameof(IDictionary.Add));
|
||||
|
||||
protected static readonly ParameterExpression ExceptionExpr = Expression.Variable(typeof(Exception), "exception");
|
||||
|
||||
protected static readonly MemberExpression ExceptionDataExpr = Expression.MakeMemberAccess(ExceptionExpr, DataProperty);
|
||||
protected static readonly MemberExpression ExceptionDataExpr = Expression.MakeMemberAccess(ExceptionExpr, DataPropertyInfo);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace Unity
|
|||
#region Constructors
|
||||
|
||||
public ConstructorDiagnostic(UnityContainer container)
|
||||
: base(container)
|
||||
: base(container, new ParametersDiagnosticProcessor())
|
||||
{
|
||||
container.Defaults.Set(typeof(Func<Type, InjectionMember, ConstructorInfo>), InjectionValidatingSelector);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Selection
|
||||
#region Selection Overrides
|
||||
|
||||
public override IEnumerable<object> Select(Type type, InjectionMember[]? injectionMembers)
|
||||
{
|
||||
|
@ -137,12 +137,6 @@ namespace Unity
|
|||
return new[] { SelectMethod(type, constructors) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects default constructor
|
||||
/// </summary>
|
||||
/// <param name="type"><see cref="Type"/> to be built</param>
|
||||
/// <param name="members">All public constructors this type implements</param>
|
||||
/// <returns></returns>
|
||||
public override object? LegacySelector(Type type, ConstructorInfo[] members)
|
||||
{
|
||||
// TODO: Add validation to legacy selector
|
||||
|
@ -230,82 +224,6 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Expression Overrides
|
||||
|
||||
public override IEnumerable<Expression> Express(ref PipelineBuilder builder)
|
||||
{
|
||||
#if NETSTANDARD1_0 || NETCOREAPP1_0
|
||||
var typeInfo = builder.Type.GetTypeInfo();
|
||||
#else
|
||||
var typeInfo = builder.Type;
|
||||
#endif
|
||||
// Validate if Type could be created
|
||||
if (typeInfo.IsInterface) return CannotConstructInterfaceExpr.Concat(builder.Express());
|
||||
|
||||
if (typeInfo.IsAbstract) return CannotConstructAbstractClassExpr.Concat(builder.Express());
|
||||
|
||||
if (typeInfo.IsSubclassOf(typeof(Delegate)))
|
||||
return CannotConstructDelegateExpr.Concat(builder.Express());
|
||||
|
||||
if (typeof(string) == builder.Type)
|
||||
return TypeIsNotConstructableExpr.Concat(builder.Express());
|
||||
|
||||
// Build expression as usual
|
||||
return base.Express(ref builder);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Expression> GetConstructorExpression(ConstructorInfo info, object? resolvers)
|
||||
{
|
||||
var parameters = info.GetParameters();
|
||||
var variables = parameters.Select(p => Expression.Variable(p.ParameterType, p.Name))
|
||||
.ToArray();
|
||||
|
||||
// Check if has Out or ByRef parameters
|
||||
var tryBlock = parameters.Any(pi => pi.ParameterType.IsByRef)
|
||||
|
||||
// Report error
|
||||
? (Expression)Expression.Throw(Expression.New(InvalidRegistrationExpressionCtor,
|
||||
Expression.Constant(CreateErrorMessage("The constructor {1} selected for type {0} has ref or out parameters. Such parameters are not supported for constructor injection.",
|
||||
info.DeclaringType, info))))
|
||||
|
||||
// Create new instance
|
||||
: Expression.Assign(
|
||||
PipelineContextExpression.Existing,
|
||||
Expression.Convert(Expression.New(info, CreateDiagnosticParameterExpressions(info.GetParameters(), resolvers)), typeof(object)));
|
||||
|
||||
//
|
||||
var thenBlock = Expression.Block(variables, CreateParameterExpressions(variables, parameters, resolvers)
|
||||
.Concat(new[] { Expression.Assign(
|
||||
PipelineContextExpression.Existing,
|
||||
Expression.Convert(
|
||||
Expression.New(info, variables), typeof(object)))}));
|
||||
|
||||
yield return Expression.IfThen(NullEqualExisting, thenBlock);
|
||||
|
||||
// Add location to dictionary and re-throw
|
||||
var catchBlock = Expression.Block(tryBlock.Type,
|
||||
Expression.Call(ExceptionDataExpr, AddMethod,
|
||||
Expression.Convert(NewGuid, typeof(object)),
|
||||
Expression.Constant(info, typeof(object))),
|
||||
Expression.Rethrow(tryBlock.Type));
|
||||
|
||||
// Create
|
||||
yield return Expression.IfThen(NullEqualExisting,
|
||||
Expression.TryCatch(tryBlock, Expression.Catch(ExceptionExpr, catchBlock)));
|
||||
// Report error
|
||||
string CreateErrorMessage(string format, Type type, MethodBase constructor)
|
||||
{
|
||||
var parameterDescriptions =
|
||||
constructor.GetParameters()
|
||||
.Select(parameter => $"{parameter.ParameterType.FullName} {parameter.Name}");
|
||||
|
||||
return string.Format(format, type.FullName, string.Join(", ", parameterDescriptions));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolver Overrides
|
||||
|
||||
public override ResolveDelegate<PipelineContext>? Build(ref PipelineBuilder builder)
|
||||
|
@ -373,7 +291,34 @@ namespace Unity
|
|||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
||||
{
|
||||
var parameterResolvers = CreateDiagnosticParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameters = info.GetParameters();
|
||||
|
||||
// Check for 'out' parameters
|
||||
if (parameters.Any(param => param.IsOut))
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
if (null == context.Existing)
|
||||
new InvalidRegistrationException($"Constructor {info} with 'out' parameters cannot be injected.", info);
|
||||
|
||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
||||
};
|
||||
}
|
||||
|
||||
// Check for 'ref' parameters
|
||||
if (parameters.Any(param => param.ParameterType.IsByRef))
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
if (null == context.Existing)
|
||||
new InvalidRegistrationException($"Constructor {info} with 'ref' parameters cannot be injected.", info);
|
||||
|
||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
||||
};
|
||||
}
|
||||
|
||||
// Create resolver
|
||||
var parameterResolvers = ParameterResolvers(parameters, resolvers).ToArray();
|
||||
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
|
@ -400,7 +345,35 @@ namespace Unity
|
|||
|
||||
protected override ResolveDelegate<PipelineContext> GetPerResolveDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
||||
{
|
||||
var parameterResolvers = CreateDiagnosticParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameters = info.GetParameters();
|
||||
|
||||
// Check for 'out' parameters
|
||||
if (parameters.Any(param => param.IsOut))
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
if (null == context.Existing)
|
||||
new InvalidRegistrationException($"Constructor {info} with 'out' parameters cannot be injected.", info);
|
||||
|
||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
||||
};
|
||||
}
|
||||
|
||||
// Check for 'ref' parameters
|
||||
if (parameters.Any(param => param.ParameterType.IsByRef))
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
if (null == context.Existing)
|
||||
new InvalidRegistrationException($"Constructor {info} with 'ref' parameters cannot be injected.", info);
|
||||
|
||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
||||
};
|
||||
}
|
||||
|
||||
// Create resolver
|
||||
var parameterResolvers = ParameterResolvers(parameters, resolvers).ToArray();
|
||||
|
||||
// PerResolve lifetime
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
|
@ -413,21 +386,65 @@ namespace Unity
|
|||
dependencies[i] = parameterResolvers[i](ref context);
|
||||
|
||||
context.Existing = info.Invoke(dependencies);
|
||||
context.Set(typeof(LifetimeManager),
|
||||
new RuntimePerResolveLifetimeManager(context.Existing));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Data.Add(Guid.NewGuid(), info);
|
||||
throw;
|
||||
}
|
||||
|
||||
context.Set(typeof(LifetimeManager),
|
||||
new RuntimePerResolveLifetimeManager(context.Existing));
|
||||
}
|
||||
|
||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression Overrides
|
||||
|
||||
public override IEnumerable<Expression> Express(ref PipelineBuilder builder)
|
||||
{
|
||||
#if NETSTANDARD1_0 || NETCOREAPP1_0
|
||||
var typeInfo = builder.Type.GetTypeInfo();
|
||||
#else
|
||||
var typeInfo = builder.Type;
|
||||
#endif
|
||||
// Validate if Type could be created
|
||||
if (typeInfo.IsInterface)
|
||||
return CannotConstructInterfaceExpr.Concat(builder.Express());
|
||||
|
||||
if (typeInfo.IsAbstract)
|
||||
return CannotConstructAbstractClassExpr.Concat(builder.Express());
|
||||
|
||||
if (typeInfo.IsSubclassOf(typeof(Delegate)))
|
||||
return CannotConstructDelegateExpr.Concat(builder.Express());
|
||||
|
||||
if (typeof(string) == builder.Type)
|
||||
return TypeIsNotConstructableExpr.Concat(builder.Express());
|
||||
|
||||
// Build expression as usual
|
||||
return base.Express(ref builder);
|
||||
}
|
||||
|
||||
|
||||
protected override Expression GetResolverExpression(ConstructorInfo info, object? resolvers)
|
||||
{
|
||||
var tryBlock = base.GetResolverExpression(info, resolvers);
|
||||
var catchBlock = Expression.Block(tryBlock.Type,
|
||||
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||
Expression.Constant(info, typeof(object))),
|
||||
Expression.Rethrow(tryBlock.Type));
|
||||
|
||||
return Expression.TryCatch(tryBlock,
|
||||
Expression.Catch(ExceptionExpr, catchBlock));
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity.Exceptions;
|
||||
using Unity.Injection;
|
||||
using Unity.Lifetime;
|
||||
|
||||
|
@ -64,9 +65,8 @@ namespace Unity
|
|||
var lifetimeManager = (LifetimeManager?)builder.Policies?.Get(typeof(LifetimeManager));
|
||||
|
||||
return lifetimeManager is PerResolveLifetimeManager
|
||||
? GetConstructorExpression(info, resolvers).Concat(new[] { SetPerBuildSingletonExpr })
|
||||
.Concat(expressions)
|
||||
: GetConstructorExpression(info, resolvers).Concat(expressions);
|
||||
? new[] { GetResolverExpression(info, resolvers), SetPerBuildSingletonExpr }.Concat(expressions)
|
||||
: new[] { GetResolverExpression(info, resolvers) }.Concat(expressions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -74,19 +74,26 @@ namespace Unity
|
|||
|
||||
#region Overrides
|
||||
|
||||
protected virtual IEnumerable<Expression> GetConstructorExpression(ConstructorInfo info, object? resolvers)
|
||||
protected override Expression GetResolverExpression(ConstructorInfo info, object? resolvers)
|
||||
{
|
||||
var parameters = info.GetParameters();
|
||||
var variables = parameters.Select(p => Expression.Variable(p.ParameterType, p.Name))
|
||||
.ToArray();
|
||||
try
|
||||
{
|
||||
var parameters = info.GetParameters();
|
||||
var variables = parameters.Select(ToVariable)
|
||||
.ToArray();
|
||||
|
||||
var thenBlock = Expression.Block(variables, CreateParameterExpressions(variables, parameters, resolvers)
|
||||
.Concat(new[] { Expression.Assign(
|
||||
return Expression.IfThen(NullEqualExisting,
|
||||
Expression.Block(variables, ParameterExpressions(variables, parameters, resolvers)
|
||||
.Concat(new[] {
|
||||
Expression.Assign(
|
||||
PipelineContextExpression.Existing,
|
||||
Expression.Convert(
|
||||
Expression.New(info, variables), typeof(object)))}));
|
||||
|
||||
yield return Expression.IfThen(NullEqualExisting, thenBlock);
|
||||
Expression.New(info, variables), typeof(object)))})));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Expression.IfThen(NullEqualExisting, Expression.Throw(Expression.Constant(new InvalidRegistrationException(ex))));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -7,12 +7,12 @@ using Unity.Utility;
|
|||
|
||||
namespace Unity
|
||||
{
|
||||
public partial class ConstructorPipeline : ParametersPipeline<ConstructorInfo>
|
||||
public partial class ConstructorPipeline : MethodBasePipeline<ConstructorInfo>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public ConstructorPipeline(UnityContainer container)
|
||||
: base(typeof(InjectionConstructorAttribute), container)
|
||||
public ConstructorPipeline(UnityContainer container, ParametersProcessor? processor = null)
|
||||
: base(typeof(InjectionConstructorAttribute), container, processor)
|
||||
{
|
||||
SelectMethod = container.ExecutionMode.IsLegacy()
|
||||
? (Func<Type, ConstructorInfo[], object?>)LegacySelector
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Unity
|
|||
|
||||
protected virtual ResolveDelegate<PipelineContext> GetResolverDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
||||
{
|
||||
var parameterResolvers = CreateParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameterResolvers = ParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ namespace Unity
|
|||
|
||||
protected virtual ResolveDelegate<PipelineContext> GetPerResolveDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
||||
{
|
||||
var parameterResolvers = CreateParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameterResolvers = ParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
// PerResolve lifetime
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Unity
|
|||
|
||||
var tryBody = Expression.Block(expressions);
|
||||
var catchBody = Expression.Block(tryBody.Type,
|
||||
Expression.IfThen(filter, Expression.Call(ExceptionDataExpr, AddMethod, Expression.Convert(NewGuid, typeof(object)), infoExpr)),
|
||||
Expression.IfThen(filter, Expression.Call(ExceptionDataExpr, AddMethodInfo, Expression.Convert(CallNewGuidExpr, typeof(object)), infoExpr)),
|
||||
Expression.Rethrow(tryBody.Type));
|
||||
|
||||
return new Expression[]
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Unity
|
|||
// Select Attributed members
|
||||
foreach (var member in type.GetDeclaredFields())
|
||||
{
|
||||
foreach(var node in AttributeFactories)
|
||||
foreach (var node in AttributeFactories)
|
||||
{
|
||||
#if NET40
|
||||
if (!member.IsDefined(node.Type, true) ||
|
||||
|
@ -75,20 +75,10 @@ namespace Unity
|
|||
}
|
||||
}
|
||||
|
||||
protected override Expression GetResolverExpression(FieldInfo field, object? resolver)
|
||||
{
|
||||
var ex = Expression.Variable(typeof(Exception));
|
||||
var exData = Expression.MakeMemberAccess(ex, DataProperty);
|
||||
var block =
|
||||
Expression.Block(field.FieldType,
|
||||
Expression.Call(exData, AddMethod,
|
||||
Expression.Convert(NewGuid, typeof(object)),
|
||||
Expression.Constant(field, typeof(object))),
|
||||
Expression.Rethrow(field.FieldType));
|
||||
#endregion
|
||||
|
||||
return Expression.TryCatch(base.GetResolverExpression(field, resolver),
|
||||
Expression.Catch(ex, block));
|
||||
}
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(FieldInfo info, object? resolver)
|
||||
{
|
||||
|
@ -109,5 +99,22 @@ namespace Unity
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(FieldInfo field, object? resolver)
|
||||
{
|
||||
var block = Expression.Block(field.FieldType,
|
||||
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||
Expression.Constant(field, typeof(object))),
|
||||
Expression.Rethrow(field.FieldType));
|
||||
|
||||
return Expression.TryCatch(base.GetResolverExpression(field, resolver),
|
||||
Expression.Catch(ExceptionExpr, block));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,21 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(FieldInfo info, object? resolver)
|
||||
{
|
||||
var value = PreProcessResolver(info, resolver);
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
info.SetValue(context.Existing, context.Resolve(info, value));
|
||||
return context.Existing;
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(FieldInfo info, object? resolver)
|
||||
|
@ -52,20 +67,5 @@ namespace Unity
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(FieldInfo info, object? resolver)
|
||||
{
|
||||
var value = PreProcessResolver(info, resolver);
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
info.SetValue(context.Existing, context.Resolve(info, value));
|
||||
return context.Existing;
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,10 @@ namespace Unity
|
|||
break;
|
||||
|
||||
|
||||
case Exception exception:
|
||||
yield return Expression.Throw(Expression.Constant(exception));
|
||||
yield break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
throw new InvalidOperationException($"Unknown MemberInfo<{typeof(TMemberInfo)}> type");
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Unity
|
|||
#region Constructors
|
||||
|
||||
public MethodDiagnostic(UnityContainer container)
|
||||
: base(container)
|
||||
: base(container, new ParametersDiagnosticProcessor())
|
||||
{
|
||||
container.Defaults.Set(typeof(Func<Type, InjectionMember, MethodInfo>), InjectionValidatingSelector);
|
||||
}
|
||||
|
@ -51,34 +51,34 @@ namespace Unity
|
|||
if (member.IsStatic)
|
||||
{
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Static method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Static methods cannot be injected");
|
||||
$"Static method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Static methods cannot be injected", member);
|
||||
}
|
||||
|
||||
if (member.IsPrivate)
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Private method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Private methods cannot be injected");
|
||||
$"Private method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Private methods cannot be injected", member);
|
||||
|
||||
if (member.IsFamily)
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Protected method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Protected methods cannot be injected");
|
||||
$"Protected method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Protected methods cannot be injected", member);
|
||||
|
||||
if (member.IsGenericMethodDefinition)
|
||||
{
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Open generic method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Open generic methods cannot be injected.");
|
||||
$"Open generic method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Open generic methods cannot be injected.", member);
|
||||
}
|
||||
|
||||
var parameters = member.GetParameters();
|
||||
if (parameters.Any(param => param.IsOut))
|
||||
{
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Methods with 'out' parameters cannot be injected.");
|
||||
$"Method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Methods with 'out' parameters cannot be injected.", member);
|
||||
}
|
||||
|
||||
if (parameters.Any(param => param.ParameterType.IsByRef))
|
||||
{
|
||||
yield return new InvalidRegistrationException(
|
||||
$"Method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Methods with 'ref' parameters cannot be injected.");
|
||||
$"Method {member.Name} on type '{member.DeclaringType.Name}' has 'ref' parameter and cannot be injected.", member);
|
||||
}
|
||||
|
||||
yield return member;
|
||||
|
@ -87,27 +87,14 @@ namespace Unity
|
|||
}
|
||||
}
|
||||
|
||||
protected override Expression GetResolverExpression(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var ex = Expression.Variable(typeof(Exception));
|
||||
var exData = Expression.MakeMemberAccess(ex, DataProperty);
|
||||
var block = Expression.Block(typeof(void),
|
||||
Expression.Call(exData, AddMethod,
|
||||
Expression.Convert(NewGuid, typeof(object)),
|
||||
Expression.Constant(info, typeof(object))),
|
||||
Expression.Rethrow(typeof(void)));
|
||||
#endregion
|
||||
|
||||
return
|
||||
Expression.TryCatch(
|
||||
Expression.Call(
|
||||
Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType),
|
||||
info, CreateDiagnosticParameterExpressions(info.GetParameters(), resolvers)),
|
||||
Expression.Catch(ex, block));
|
||||
}
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var parameterResolvers = CreateDiagnosticParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameterResolvers = ParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
return (ref PipelineContext c) =>
|
||||
{
|
||||
try
|
||||
|
@ -129,6 +116,23 @@ namespace Unity
|
|||
return c.Existing;
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var block = Expression.Block(typeof(void),
|
||||
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||
Expression.Constant(info, typeof(object))),
|
||||
Expression.Rethrow(typeof(void)));
|
||||
|
||||
return Expression.TryCatch(base.GetResolverExpression(info, resolvers),
|
||||
Expression.Catch(ExceptionExpr, block));
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ using Unity.Resolution;
|
|||
|
||||
namespace Unity
|
||||
{
|
||||
public partial class MethodPipeline : ParametersPipeline<MethodInfo>
|
||||
public partial class MethodPipeline : MethodBasePipeline<MethodInfo>
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public MethodPipeline(UnityContainer container)
|
||||
: base(typeof(InjectionMethodAttribute), container)
|
||||
public MethodPipeline(UnityContainer container, ParametersProcessor? processor = null)
|
||||
: base(typeof(InjectionMethodAttribute), container, processor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,29 +36,11 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var parameters = info.GetParameters();
|
||||
var variables = parameters.Select(p => Expression.Variable(p.ParameterType, p.Name))
|
||||
.ToArray();
|
||||
|
||||
return Expression.Block(variables, CreateParameterExpressions(variables, parameters, resolvers)
|
||||
.Concat(new[] {
|
||||
Expression.Call(
|
||||
Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType),
|
||||
info, variables) }));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var parameterResolvers = CreateParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
var parameterResolvers = ParameterResolvers(info.GetParameters(), resolvers).ToArray();
|
||||
return (ref PipelineContext c) =>
|
||||
{
|
||||
if (null == c.Existing) return c.Existing;
|
||||
|
@ -74,5 +56,23 @@ namespace Unity
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(MethodInfo info, object? resolvers)
|
||||
{
|
||||
var parameters = info.GetParameters();
|
||||
var variables = parameters.Select(ToVariable)
|
||||
.ToArray();
|
||||
|
||||
return Expression.Block(variables, ParameterExpressions(variables, parameters, resolvers)
|
||||
.Concat(new[] {
|
||||
Expression.Call(
|
||||
Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType),
|
||||
info, variables) }));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +1,75 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Unity.Exceptions;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public abstract partial class ParametersPipeline<TMemberInfo>
|
||||
public partial class ParametersProcessor
|
||||
{
|
||||
protected virtual IEnumerable<ResolveDelegate<PipelineContext>> CreateParameterResolvers(ParameterInfo[] parameters, object? injectors = null)
|
||||
public ResolveDelegate<PipelineContext> ParameterResolver(ParameterInfo parameter)
|
||||
=> ParameterResolverFactory(parameter, FromAttribute(parameter));
|
||||
|
||||
public virtual ResolveDelegate<PipelineContext> ParameterResolver(ParameterInfo parameter, object injector)
|
||||
=> ParameterResolverFactory(parameter, PreProcessResolver(parameter, injector));
|
||||
|
||||
protected virtual ResolveDelegate<PipelineContext> ParameterResolverFactory(ParameterInfo parameter, object resolver)
|
||||
{
|
||||
object[]? resolvers = null != injectors && injectors is object[] array && 0 != array.Length ? array : null;
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
#if NET40
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
#else
|
||||
if (!parameter.HasDefaultValue)
|
||||
#endif
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
var resolver = null == resolvers
|
||||
? FromAttribute(parameter)
|
||||
: PreProcessResolver(parameter, resolvers[i]);
|
||||
return (ref PipelineContext context) => context.Resolve(parameter, resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
var defaultValue = !(parameter.DefaultValue is DBNull) ? parameter.DefaultValue : null;
|
||||
#else
|
||||
if (!parameter.HasDefaultValue)
|
||||
var defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null;
|
||||
#endif
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
// Plain vanilla case
|
||||
yield return (ref PipelineContext context) => context.Resolve(parameter, resolver);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
var defaultValue = !(parameter.DefaultValue is DBNull) ? parameter.DefaultValue : null;
|
||||
#else
|
||||
var defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null;
|
||||
#endif
|
||||
yield return (ref PipelineContext context) =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region Attribute Resolver Factories
|
||||
|
||||
protected virtual ResolveDelegate<PipelineContext> DependencyResolverFactory(Attribute attribute, ParameterInfo info, object? value = null)
|
||||
{
|
||||
return (ref PipelineContext context) => context.Resolve(info.ParameterType, ((DependencyResolutionAttribute)attribute).Name);
|
||||
}
|
||||
|
||||
protected virtual ResolveDelegate<PipelineContext> OptionalDependencyResolverFactory(Attribute attribute, ParameterInfo info, object? value = null)
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(info.ParameterType, ((DependencyResolutionAttribute)attribute).Name);
|
||||
}
|
||||
catch (Exception ex) when (!(ex is CircularDependencyException))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,133 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public abstract partial class ParametersPipeline<TMemberInfo>
|
||||
public partial class ParametersDiagnosticProcessor : ParametersProcessor
|
||||
{
|
||||
#region Diagnostic Parameter Factories
|
||||
|
||||
protected virtual IEnumerable<Expression> CreateDiagnosticParameterExpressions(ParameterInfo[] parameters, object? injectors = null)
|
||||
protected override ResolveDelegate<PipelineContext> ParameterResolverFactory(ParameterInfo parameter, object resolver)
|
||||
{
|
||||
object[]? resolvers = null != injectors && injectors is object[] array && 0 != array.Length ? array : null;
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
var resolver = null == resolvers
|
||||
? FromAttribute(parameter)
|
||||
: PreProcessResolver(parameter, resolvers[i]);
|
||||
|
||||
// Check if has default value
|
||||
|
||||
#if NET40
|
||||
Expression defaultValueExpr = null;
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
#else
|
||||
var defaultValueExpr = parameter.HasDefaultValue
|
||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||
: null;
|
||||
|
||||
if (!parameter.HasDefaultValue)
|
||||
if (!parameter.HasDefaultValue)
|
||||
#endif
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
var ex = Expression.Variable(typeof(Exception));
|
||||
var exData = Expression.MakeMemberAccess(ex, DataProperty);
|
||||
var block = Expression.Block(parameter.ParameterType,
|
||||
Expression.Call(exData, AddMethod,
|
||||
Expression.Convert(NewGuid, typeof(object)),
|
||||
Expression.Constant(parameter, typeof(object))),
|
||||
Expression.Rethrow(parameter.ParameterType));
|
||||
|
||||
var tryBlock = Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameter.ParameterType);
|
||||
|
||||
yield return Expression.TryCatch(tryBlock, Expression.Catch(ex, block));
|
||||
}
|
||||
else
|
||||
{
|
||||
var variable = Expression.Variable(parameter.ParameterType);
|
||||
var resolve = Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameter.ParameterType);
|
||||
|
||||
yield return Expression.Block(new[] { variable }, new Expression[]
|
||||
try
|
||||
{
|
||||
Expression.TryCatch(
|
||||
Expression.Assign(variable, resolve),
|
||||
Expression.Catch(typeof(Exception),
|
||||
Expression.Assign(variable, defaultValueExpr))),
|
||||
variable
|
||||
});
|
||||
}
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Data.Add(Guid.NewGuid(), parameter);
|
||||
throw;
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
var defaultValue = !(parameter.DefaultValue is DBNull) ? parameter.DefaultValue : null;
|
||||
#else
|
||||
var defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null;
|
||||
#endif
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<ResolveDelegate<PipelineContext>> CreateDiagnosticParameterResolvers(ParameterInfo[] parameters, object? injectors = null)
|
||||
protected override Expression ParameterExpressionFactory(ParameterExpression expression, ParameterInfo parameter, object resolver)
|
||||
{
|
||||
object[]? resolvers = null != injectors && injectors is object[] array && 0 != array.Length ? array : null;
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
var resolver = null == resolvers
|
||||
? FromAttribute(parameter)
|
||||
: PreProcessResolver(parameter, resolvers[i]);
|
||||
var tryBlock = base.ParameterExpressionFactory(expression, parameter, resolver);
|
||||
var catchBlock = Expression.Block(tryBlock.Type,
|
||||
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||
Expression.Constant(parameter, typeof(object))),
|
||||
Expression.Rethrow(tryBlock.Type));
|
||||
|
||||
// TODO: Add diagnostic for parameters
|
||||
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
#else
|
||||
if (!parameter.HasDefaultValue)
|
||||
#endif
|
||||
{
|
||||
// Plain vanilla case
|
||||
yield return (ref PipelineContext context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Data.Add(Guid.NewGuid(), parameter);
|
||||
throw;
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
var defaultValue = !(parameter.DefaultValue is DBNull) ? parameter.DefaultValue : null;
|
||||
#else
|
||||
var defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null;
|
||||
#endif
|
||||
yield return (ref PipelineContext context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(parameter, resolver);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return Expression.TryCatch(tryBlock,
|
||||
Expression.Catch(ExceptionExpr, catchBlock));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,60 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public abstract partial class ParametersPipeline<TMemberInfo>
|
||||
public partial class ParametersProcessor
|
||||
{
|
||||
protected virtual IEnumerable<Expression> CreateParameterExpressions(ParameterExpression[] expressions, ParameterInfo[] parameters, object? injectors)
|
||||
public Expression ParameterExpression(ParameterExpression expression, ParameterInfo parameter)
|
||||
=> ParameterExpressionFactory(expression, parameter, FromAttribute(parameter));
|
||||
|
||||
public virtual Expression ParameterExpression(ParameterExpression expression, ParameterInfo parameter, object injector)
|
||||
=> ParameterExpressionFactory(expression, parameter, PreProcessResolver(parameter, injector));
|
||||
|
||||
protected virtual Expression ParameterExpressionFactory(ParameterExpression expression, ParameterInfo parameter, object resolver)
|
||||
{
|
||||
object[]? resolvers = null != injectors && injectors is object[] array && 0 != array.Length ? array : null;
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameterExpr = expressions[i];
|
||||
var parameterInfo = parameters[i];
|
||||
var resolver = null == resolvers
|
||||
? FromAttribute(parameterInfo)
|
||||
: PreProcessResolver(parameterInfo, resolvers[i]);
|
||||
|
||||
// Check if has default value
|
||||
// Check if has default value
|
||||
#if NET40
|
||||
var defaultValueExpr = parameter.DefaultValue is DBNull
|
||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||
: null;
|
||||
var defaultValueExpr = parameter.DefaultValue is DBNull
|
||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||
: null;
|
||||
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
if (parameter.DefaultValue is DBNull)
|
||||
#else
|
||||
var defaultValueExpr = parameterInfo.HasDefaultValue
|
||||
? Expression.Constant(parameterInfo.DefaultValue, parameterInfo.ParameterType)
|
||||
: null;
|
||||
var defaultValueExpr = parameter.HasDefaultValue
|
||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||
: null;
|
||||
|
||||
if (!parameterInfo.HasDefaultValue)
|
||||
if (!parameter.HasDefaultValue)
|
||||
#endif
|
||||
{
|
||||
// Plain vanilla case
|
||||
yield return Expression.Assign(parameterExpr, Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameterInfo, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameterInfo.ParameterType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolve = Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameterInfo, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameterInfo.ParameterType);
|
||||
{
|
||||
// Plain vanilla case
|
||||
return Expression.Assign(expression, Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameter.ParameterType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolve = Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolveParameterMethod,
|
||||
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||
Expression.Constant(resolver, typeof(object))),
|
||||
parameter.ParameterType);
|
||||
|
||||
yield return Expression.TryCatch(
|
||||
Expression.Assign(parameterExpr, resolve),
|
||||
Expression.Catch(typeof(Exception),
|
||||
Expression.Assign(parameterExpr, defaultValueExpr)));
|
||||
}
|
||||
return Expression.TryCatch(
|
||||
Expression.Assign(expression, resolve),
|
||||
Expression.Catch(typeof(Exception),
|
||||
Expression.Assign(expression, defaultValueExpr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity.Exceptions;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public abstract partial class ParametersPipeline<TMemberInfo> : MemberPipeline<TMemberInfo, object[]>
|
||||
where TMemberInfo : MethodBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
protected readonly UnityContainer Container;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
protected ParametersPipeline(Type attribute, UnityContainer container)
|
||||
: base(container)
|
||||
{
|
||||
Container = container;
|
||||
Markers = new[] { attribute };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Members
|
||||
|
||||
public void AddMarkers(IEnumerable<Type> attributes)
|
||||
{
|
||||
Markers = Markers.Concat(attributes).ToArray();
|
||||
}
|
||||
|
||||
public Type[] Markers { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Overrides
|
||||
|
||||
protected override Type MemberType(TMemberInfo info) => info.DeclaringType;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implementation
|
||||
|
||||
private object PreProcessResolver(ParameterInfo parameter, object resolver)
|
||||
{
|
||||
switch (resolver)
|
||||
{
|
||||
case IResolve policy:
|
||||
return (ResolveDelegate<PipelineContext>)policy.Resolve;
|
||||
|
||||
case IResolverFactory<ParameterInfo> factory:
|
||||
return factory.GetResolver<PipelineContext>(parameter);
|
||||
|
||||
case Type type:
|
||||
return
|
||||
typeof(Type) == parameter.ParameterType
|
||||
? type
|
||||
: type == parameter.ParameterType
|
||||
? FromAttribute(parameter)
|
||||
: FromType(type);
|
||||
}
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private object FromType(Type type)
|
||||
{
|
||||
return (ResolveDelegate<PipelineContext>)((ref PipelineContext context) => context.Resolve(type, (string?)null));
|
||||
}
|
||||
|
||||
private object FromAttribute(ParameterInfo info)
|
||||
{
|
||||
#if NET40
|
||||
var defaultValue = !(info.DefaultValue is DBNull) ? info.DefaultValue : null;
|
||||
#else
|
||||
var defaultValue = info.HasDefaultValue ? info.DefaultValue : null;
|
||||
#endif
|
||||
foreach (var node in AttributeFactories)
|
||||
{
|
||||
if (null == node.Factory) continue;
|
||||
var attribute = info.GetCustomAttribute(node.Type);
|
||||
if (null == attribute) continue;
|
||||
|
||||
// If found match, use provided factory to create expression
|
||||
return node.Factory(attribute, info, defaultValue);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
protected bool CanResolve(ParameterInfo info)
|
||||
{
|
||||
foreach (var node in AttributeFactories)
|
||||
{
|
||||
if (null == node.Factory) continue;
|
||||
var attribute = info.GetCustomAttribute(node.Type);
|
||||
if (null == attribute) continue;
|
||||
|
||||
// If found match, use provided factory to create expression
|
||||
return Container.CanResolve(info.ParameterType, node.Name(attribute));
|
||||
}
|
||||
|
||||
return Container.CanResolve(info.ParameterType, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Attribute Factories
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> DependencyResolverFactory(Attribute attribute, object info, object? value = null)
|
||||
{
|
||||
return (ref PipelineContext context) => context.Resolve(((ParameterInfo)info).ParameterType, ((DependencyResolutionAttribute)attribute).Name);
|
||||
}
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> OptionalDependencyResolverFactory(Attribute attribute, object info, object? value = null)
|
||||
{
|
||||
return (ref PipelineContext context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return context.Resolve(((ParameterInfo)info).ParameterType,
|
||||
((DependencyResolutionAttribute)attribute).Name);
|
||||
}
|
||||
catch (Exception ex) when (!(ex is CircularDependencyException))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public partial class ParametersProcessor
|
||||
{
|
||||
#region Fields
|
||||
|
||||
protected static readonly Expression CallNewGuidExpr = Expression.Call(typeof(Guid).GetTypeInfo().GetDeclaredMethod(nameof(Guid.NewGuid)));
|
||||
|
||||
protected static readonly PropertyInfo DataPropertyInfo = typeof(Exception).GetTypeInfo().GetDeclaredProperty(nameof(Exception.Data));
|
||||
|
||||
protected static readonly MethodInfo AddMethodInfo = typeof(IDictionary).GetTypeInfo().GetDeclaredMethod(nameof(IDictionary.Add));
|
||||
|
||||
protected static readonly ParameterExpression ExceptionExpr = Expression.Variable(typeof(Exception), "exception");
|
||||
|
||||
protected static readonly MemberExpression ExceptionDataExpr = Expression.MakeMemberAccess(ExceptionExpr, DataPropertyInfo);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ParametersProcessor()
|
||||
{
|
||||
AttributeFactories = new[]
|
||||
{
|
||||
new AttributeFactory(typeof(DependencyAttribute), (a)=>((DependencyResolutionAttribute)a).Name, DependencyResolverFactory),
|
||||
new AttributeFactory(typeof(OptionalDependencyAttribute), (a)=>((DependencyResolutionAttribute)a).Name, OptionalDependencyResolverFactory),
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Members
|
||||
|
||||
// TODO: Requires optimization
|
||||
public void AddFactories(IEnumerable<AttributeFactory> factories)
|
||||
{
|
||||
AttributeFactories = AttributeFactories.Concat(factories).ToArray();
|
||||
}
|
||||
|
||||
public AttributeFactory[] AttributeFactories { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Implementation
|
||||
|
||||
private object PreProcessResolver(ParameterInfo parameter, object resolver)
|
||||
{
|
||||
switch (resolver)
|
||||
{
|
||||
case IResolve policy:
|
||||
return (ResolveDelegate<PipelineContext>)policy.Resolve;
|
||||
|
||||
case IResolverFactory<ParameterInfo> factory:
|
||||
return factory.GetResolver<PipelineContext>(parameter);
|
||||
|
||||
case Type type:
|
||||
return
|
||||
typeof(Type) == parameter.ParameterType
|
||||
? type
|
||||
: type == parameter.ParameterType
|
||||
? FromAttribute(parameter)
|
||||
: FromType(type);
|
||||
}
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private object FromType(Type type)
|
||||
{
|
||||
return (ResolveDelegate<PipelineContext>)((ref PipelineContext context) => context.Resolve(type, (string?)null));
|
||||
}
|
||||
|
||||
private object FromAttribute(ParameterInfo info)
|
||||
{
|
||||
#if NET40
|
||||
var defaultValue = !(info.DefaultValue is DBNull) ? info.DefaultValue : null;
|
||||
#else
|
||||
var defaultValue = info.HasDefaultValue ? info.DefaultValue : null;
|
||||
#endif
|
||||
foreach (var node in AttributeFactories)
|
||||
{
|
||||
if (null == node.Factory) continue;
|
||||
var attribute = info.GetCustomAttribute(node.Type);
|
||||
if (null == attribute) continue;
|
||||
|
||||
// If found match, use provided factory to create expression
|
||||
return node.Factory(attribute, info, defaultValue);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Nested Types
|
||||
|
||||
public struct AttributeFactory
|
||||
{
|
||||
public readonly Type Type;
|
||||
public Func<Attribute, ParameterInfo, object?, ResolveDelegate<PipelineContext>> Factory;
|
||||
public Func<Attribute, string> Name;
|
||||
|
||||
public AttributeFactory(Type type, Func<Attribute, string> getName, Func<Attribute, ParameterInfo, object?, ResolveDelegate<PipelineContext>> factory)
|
||||
{
|
||||
Type = type;
|
||||
Name = getName;
|
||||
Factory = factory;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Unity;
|
||||
using Unity.Exceptions;
|
||||
using Unity.Injection;
|
||||
using Unity.Resolution;
|
||||
|
@ -74,20 +73,10 @@ namespace Unity
|
|||
}
|
||||
}
|
||||
|
||||
protected override Expression GetResolverExpression(PropertyInfo property, object? resolver)
|
||||
{
|
||||
var ex = Expression.Variable(typeof(Exception));
|
||||
var exData = Expression.MakeMemberAccess(ex, DataProperty);
|
||||
var block =
|
||||
Expression.Block(property.PropertyType,
|
||||
Expression.Call(exData, AddMethod,
|
||||
Expression.Convert(NewGuid, typeof(object)),
|
||||
Expression.Constant(property, typeof(object))),
|
||||
Expression.Rethrow(property.PropertyType));
|
||||
#endregion
|
||||
|
||||
return Expression.TryCatch(base.GetResolverExpression(property, resolver),
|
||||
Expression.Catch(ex, block));
|
||||
}
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
||||
{
|
||||
|
@ -112,5 +101,22 @@ namespace Unity
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(PropertyInfo property, object? resolver)
|
||||
{
|
||||
var block = Expression.Block(property.PropertyType,
|
||||
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||
Expression.Constant(property, typeof(object))),
|
||||
Expression.Rethrow(property.PropertyType));
|
||||
|
||||
return Expression.TryCatch(base.GetResolverExpression(property, resolver),
|
||||
Expression.Catch(ExceptionExpr, block));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,23 +44,6 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(PropertyInfo info, object? resolver)
|
||||
{
|
||||
return Expression.Assign(
|
||||
Expression.Property(Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType), info),
|
||||
Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolvePropertyMethod,
|
||||
Expression.Constant(info, typeof(PropertyInfo)),
|
||||
Expression.Constant(PreProcessResolver(info, resolver), typeof(object))),
|
||||
info.PropertyType));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolution
|
||||
|
||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
||||
|
@ -78,5 +61,22 @@ namespace Unity
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Expression
|
||||
|
||||
protected override Expression GetResolverExpression(PropertyInfo info, object? resolver)
|
||||
{
|
||||
return Expression.Assign(
|
||||
Expression.Property(Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType), info),
|
||||
Expression.Convert(
|
||||
Expression.Call(PipelineContextExpression.Context,
|
||||
PipelineContextExpression.ResolvePropertyMethod,
|
||||
Expression.Constant(info, typeof(PropertyInfo)),
|
||||
Expression.Constant(PreProcessResolver(info, resolver), typeof(object))),
|
||||
info.PropertyType));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ namespace Unity
|
|||
var builder = new StringBuilder();
|
||||
builder.AppendLine(ex.Message);
|
||||
builder.AppendLine(line);
|
||||
builder.AppendLine("Exception occurred while:");
|
||||
builder.AppendLine("Exception occurred:");
|
||||
|
||||
foreach (DictionaryEntry item in ex.Data)
|
||||
builder.AppendLine(DataToString(item.Value));
|
||||
|
|
Загрузка…
Ссылка в новой задаче