Restore point
This commit is contained in:
Родитель
063765d99f
Коммит
61ffdbdb1a
|
@ -4,10 +4,23 @@ namespace Unity.Exceptions
|
||||||
{
|
{
|
||||||
public class InvalidRegistrationException : Exception
|
public class InvalidRegistrationException : Exception
|
||||||
{
|
{
|
||||||
|
internal InvalidRegistrationException(Exception ex)
|
||||||
|
: base(ex.Message, ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
internal InvalidRegistrationException(string message)
|
internal InvalidRegistrationException(string message)
|
||||||
: base(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;
|
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 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
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace Unity
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public ConstructorDiagnostic(UnityContainer container)
|
public ConstructorDiagnostic(UnityContainer container)
|
||||||
: base(container)
|
: base(container, new ParametersDiagnosticProcessor())
|
||||||
{
|
{
|
||||||
container.Defaults.Set(typeof(Func<Type, InjectionMember, ConstructorInfo>), InjectionValidatingSelector);
|
container.Defaults.Set(typeof(Func<Type, InjectionMember, ConstructorInfo>), InjectionValidatingSelector);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ namespace Unity
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Selection
|
#region Selection Overrides
|
||||||
|
|
||||||
public override IEnumerable<object> Select(Type type, InjectionMember[]? injectionMembers)
|
public override IEnumerable<object> Select(Type type, InjectionMember[]? injectionMembers)
|
||||||
{
|
{
|
||||||
|
@ -137,12 +137,6 @@ namespace Unity
|
||||||
return new[] { SelectMethod(type, constructors) };
|
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)
|
public override object? LegacySelector(Type type, ConstructorInfo[] members)
|
||||||
{
|
{
|
||||||
// TODO: Add validation to legacy selector
|
// TODO: Add validation to legacy selector
|
||||||
|
@ -230,82 +224,6 @@ namespace Unity
|
||||||
#endregion
|
#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
|
#region Resolver Overrides
|
||||||
|
|
||||||
public override ResolveDelegate<PipelineContext>? Build(ref PipelineBuilder builder)
|
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)
|
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) =>
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
|
@ -400,7 +345,35 @@ namespace Unity
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetPerResolveDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
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
|
// PerResolve lifetime
|
||||||
return (ref PipelineContext context) =>
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
|
@ -413,21 +386,65 @@ namespace Unity
|
||||||
dependencies[i] = parameterResolvers[i](ref context);
|
dependencies[i] = parameterResolvers[i](ref context);
|
||||||
|
|
||||||
context.Existing = info.Invoke(dependencies);
|
context.Existing = info.Invoke(dependencies);
|
||||||
|
context.Set(typeof(LifetimeManager),
|
||||||
|
new RuntimePerResolveLifetimeManager(context.Existing));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ex.Data.Add(Guid.NewGuid(), info);
|
ex.Data.Add(Guid.NewGuid(), info);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Set(typeof(LifetimeManager),
|
|
||||||
new RuntimePerResolveLifetimeManager(context.Existing));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null == pipeline ? context.Existing : pipeline.Invoke(ref context);
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Unity.Exceptions;
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
|
||||||
|
@ -64,9 +65,8 @@ namespace Unity
|
||||||
var lifetimeManager = (LifetimeManager?)builder.Policies?.Get(typeof(LifetimeManager));
|
var lifetimeManager = (LifetimeManager?)builder.Policies?.Get(typeof(LifetimeManager));
|
||||||
|
|
||||||
return lifetimeManager is PerResolveLifetimeManager
|
return lifetimeManager is PerResolveLifetimeManager
|
||||||
? GetConstructorExpression(info, resolvers).Concat(new[] { SetPerBuildSingletonExpr })
|
? new[] { GetResolverExpression(info, resolvers), SetPerBuildSingletonExpr }.Concat(expressions)
|
||||||
.Concat(expressions)
|
: new[] { GetResolverExpression(info, resolvers) }.Concat(expressions);
|
||||||
: GetConstructorExpression(info, resolvers).Concat(expressions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -74,19 +74,26 @@ namespace Unity
|
||||||
|
|
||||||
#region Overrides
|
#region Overrides
|
||||||
|
|
||||||
protected virtual IEnumerable<Expression> GetConstructorExpression(ConstructorInfo info, object? resolvers)
|
protected override Expression GetResolverExpression(ConstructorInfo info, object? resolvers)
|
||||||
{
|
{
|
||||||
var parameters = info.GetParameters();
|
try
|
||||||
var variables = parameters.Select(p => Expression.Variable(p.ParameterType, p.Name))
|
{
|
||||||
.ToArray();
|
var parameters = info.GetParameters();
|
||||||
|
var variables = parameters.Select(ToVariable)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
var thenBlock = Expression.Block(variables, CreateParameterExpressions(variables, parameters, resolvers)
|
return Expression.IfThen(NullEqualExisting,
|
||||||
.Concat(new[] { Expression.Assign(
|
Expression.Block(variables, ParameterExpressions(variables, parameters, resolvers)
|
||||||
|
.Concat(new[] {
|
||||||
|
Expression.Assign(
|
||||||
PipelineContextExpression.Existing,
|
PipelineContextExpression.Existing,
|
||||||
Expression.Convert(
|
Expression.Convert(
|
||||||
Expression.New(info, variables), typeof(object)))}));
|
Expression.New(info, variables), typeof(object)))})));
|
||||||
|
}
|
||||||
yield return Expression.IfThen(NullEqualExisting, thenBlock);
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Expression.IfThen(NullEqualExisting, Expression.Throw(Expression.Constant(new InvalidRegistrationException(ex))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -7,12 +7,12 @@ using Unity.Utility;
|
||||||
|
|
||||||
namespace Unity
|
namespace Unity
|
||||||
{
|
{
|
||||||
public partial class ConstructorPipeline : ParametersPipeline<ConstructorInfo>
|
public partial class ConstructorPipeline : MethodBasePipeline<ConstructorInfo>
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public ConstructorPipeline(UnityContainer container)
|
public ConstructorPipeline(UnityContainer container, ParametersProcessor? processor = null)
|
||||||
: base(typeof(InjectionConstructorAttribute), container)
|
: base(typeof(InjectionConstructorAttribute), container, processor)
|
||||||
{
|
{
|
||||||
SelectMethod = container.ExecutionMode.IsLegacy()
|
SelectMethod = container.ExecutionMode.IsLegacy()
|
||||||
? (Func<Type, ConstructorInfo[], object?>)LegacySelector
|
? (Func<Type, ConstructorInfo[], object?>)LegacySelector
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace Unity
|
||||||
|
|
||||||
protected virtual ResolveDelegate<PipelineContext> GetResolverDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
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) =>
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
|
@ -107,7 +107,7 @@ namespace Unity
|
||||||
|
|
||||||
protected virtual ResolveDelegate<PipelineContext> GetPerResolveDelegate(ConstructorInfo info, object? resolvers, ResolveDelegate<PipelineContext>? pipeline)
|
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
|
// PerResolve lifetime
|
||||||
return (ref PipelineContext context) =>
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace Unity
|
||||||
|
|
||||||
var tryBody = Expression.Block(expressions);
|
var tryBody = Expression.Block(expressions);
|
||||||
var catchBody = Expression.Block(tryBody.Type,
|
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));
|
Expression.Rethrow(tryBody.Type));
|
||||||
|
|
||||||
return new Expression[]
|
return new Expression[]
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Unity
|
||||||
// Select Attributed members
|
// Select Attributed members
|
||||||
foreach (var member in type.GetDeclaredFields())
|
foreach (var member in type.GetDeclaredFields())
|
||||||
{
|
{
|
||||||
foreach(var node in AttributeFactories)
|
foreach (var node in AttributeFactories)
|
||||||
{
|
{
|
||||||
#if NET40
|
#if NET40
|
||||||
if (!member.IsDefined(node.Type, true) ||
|
if (!member.IsDefined(node.Type, true) ||
|
||||||
|
@ -75,20 +75,10 @@ namespace Unity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Expression GetResolverExpression(FieldInfo field, object? resolver)
|
#endregion
|
||||||
{
|
|
||||||
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));
|
|
||||||
|
|
||||||
return Expression.TryCatch(base.GetResolverExpression(field, resolver),
|
|
||||||
Expression.Catch(ex, block));
|
#region Resolution
|
||||||
}
|
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(FieldInfo info, object? resolver)
|
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(FieldInfo info, object? resolver)
|
||||||
{
|
{
|
||||||
|
@ -109,5 +99,22 @@ namespace Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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
|
#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
|
#region Expression
|
||||||
|
|
||||||
protected override Expression GetResolverExpression(FieldInfo info, object? resolver)
|
protected override Expression GetResolverExpression(FieldInfo info, object? resolver)
|
||||||
|
@ -52,20 +67,5 @@ namespace Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case Exception exception:
|
||||||
|
yield return Expression.Throw(Expression.Constant(exception));
|
||||||
|
yield break;
|
||||||
|
|
||||||
// Unknown
|
// Unknown
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"Unknown MemberInfo<{typeof(TMemberInfo)}> type");
|
throw new InvalidOperationException($"Unknown MemberInfo<{typeof(TMemberInfo)}> type");
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Unity
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public MethodDiagnostic(UnityContainer container)
|
public MethodDiagnostic(UnityContainer container)
|
||||||
: base(container)
|
: base(container, new ParametersDiagnosticProcessor())
|
||||||
{
|
{
|
||||||
container.Defaults.Set(typeof(Func<Type, InjectionMember, MethodInfo>), InjectionValidatingSelector);
|
container.Defaults.Set(typeof(Func<Type, InjectionMember, MethodInfo>), InjectionValidatingSelector);
|
||||||
}
|
}
|
||||||
|
@ -51,34 +51,34 @@ namespace Unity
|
||||||
if (member.IsStatic)
|
if (member.IsStatic)
|
||||||
{
|
{
|
||||||
yield return new InvalidRegistrationException(
|
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)
|
if (member.IsPrivate)
|
||||||
yield return new InvalidRegistrationException(
|
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)
|
if (member.IsFamily)
|
||||||
yield return new InvalidRegistrationException(
|
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)
|
if (member.IsGenericMethodDefinition)
|
||||||
{
|
{
|
||||||
yield return new InvalidRegistrationException(
|
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();
|
var parameters = member.GetParameters();
|
||||||
if (parameters.Any(param => param.IsOut))
|
if (parameters.Any(param => param.IsOut))
|
||||||
{
|
{
|
||||||
yield return new InvalidRegistrationException(
|
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))
|
if (parameters.Any(param => param.ParameterType.IsByRef))
|
||||||
{
|
{
|
||||||
yield return new InvalidRegistrationException(
|
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;
|
yield return member;
|
||||||
|
@ -87,27 +87,14 @@ namespace Unity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Expression GetResolverExpression(MethodInfo info, object? resolvers)
|
#endregion
|
||||||
{
|
|
||||||
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)));
|
|
||||||
|
|
||||||
return
|
|
||||||
Expression.TryCatch(
|
#region Resolution
|
||||||
Expression.Call(
|
|
||||||
Expression.Convert(PipelineContextExpression.Existing, info.DeclaringType),
|
|
||||||
info, CreateDiagnosticParameterExpressions(info.GetParameters(), resolvers)),
|
|
||||||
Expression.Catch(ex, block));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(MethodInfo info, object? resolvers)
|
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) =>
|
return (ref PipelineContext c) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -129,6 +116,23 @@ namespace Unity
|
||||||
return c.Existing;
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@ using Unity.Resolution;
|
||||||
|
|
||||||
namespace Unity
|
namespace Unity
|
||||||
{
|
{
|
||||||
public partial class MethodPipeline : ParametersPipeline<MethodInfo>
|
public partial class MethodPipeline : MethodBasePipeline<MethodInfo>
|
||||||
{
|
{
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public MethodPipeline(UnityContainer container)
|
public MethodPipeline(UnityContainer container, ParametersProcessor? processor = null)
|
||||||
: base(typeof(InjectionMethodAttribute), container)
|
: base(typeof(InjectionMethodAttribute), container, processor)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,29 +36,11 @@ namespace Unity
|
||||||
#endregion
|
#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
|
#region Resolution
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(MethodInfo info, object? resolvers)
|
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) =>
|
return (ref PipelineContext c) =>
|
||||||
{
|
{
|
||||||
if (null == c.Existing) return c.Existing;
|
if (null == c.Existing) return c.Existing;
|
||||||
|
@ -74,5 +56,23 @@ namespace Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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 System.Reflection;
|
||||||
|
using Unity.Exceptions;
|
||||||
using Unity.Resolution;
|
using Unity.Resolution;
|
||||||
|
|
||||||
namespace Unity
|
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;
|
#if NET40
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
if (parameter.DefaultValue is DBNull)
|
||||||
|
#else
|
||||||
|
if (!parameter.HasDefaultValue)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
var parameter = parameters[i];
|
return (ref PipelineContext context) => context.Resolve(parameter, resolver);
|
||||||
var resolver = null == resolvers
|
}
|
||||||
? FromAttribute(parameter)
|
else
|
||||||
: PreProcessResolver(parameter, resolvers[i]);
|
{
|
||||||
|
// Check if has default value
|
||||||
#if NET40
|
#if NET40
|
||||||
if (parameter.DefaultValue is DBNull)
|
var defaultValue = !(parameter.DefaultValue is DBNull) ? parameter.DefaultValue : null;
|
||||||
#else
|
#else
|
||||||
if (!parameter.HasDefaultValue)
|
var defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null;
|
||||||
#endif
|
#endif
|
||||||
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
// Plain vanilla case
|
try
|
||||||
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
|
return context.Resolve(parameter, resolver);
|
||||||
{
|
}
|
||||||
return context.Resolve(parameter, resolver);
|
catch
|
||||||
}
|
{
|
||||||
catch
|
return defaultValue;
|
||||||
{
|
}
|
||||||
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;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Unity.Resolution;
|
using Unity.Resolution;
|
||||||
|
|
||||||
namespace Unity
|
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
|
#if NET40
|
||||||
Expression defaultValueExpr = null;
|
if (parameter.DefaultValue is DBNull)
|
||||||
if (parameter.DefaultValue is DBNull)
|
|
||||||
#else
|
#else
|
||||||
var defaultValueExpr = parameter.HasDefaultValue
|
if (!parameter.HasDefaultValue)
|
||||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (!parameter.HasDefaultValue)
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
return (ref PipelineContext context) =>
|
||||||
{
|
{
|
||||||
var ex = Expression.Variable(typeof(Exception));
|
try
|
||||||
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[]
|
|
||||||
{
|
{
|
||||||
Expression.TryCatch(
|
return context.Resolve(parameter, resolver);
|
||||||
Expression.Assign(variable, resolve),
|
}
|
||||||
Expression.Catch(typeof(Exception),
|
catch (Exception ex)
|
||||||
Expression.Assign(variable, defaultValueExpr))),
|
{
|
||||||
variable
|
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;
|
var tryBlock = base.ParameterExpressionFactory(expression, parameter, resolver);
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
var catchBlock = Expression.Block(tryBlock.Type,
|
||||||
{
|
Expression.Call(ExceptionDataExpr, AddMethodInfo,
|
||||||
var parameter = parameters[i];
|
Expression.Convert(CallNewGuidExpr, typeof(object)),
|
||||||
var resolver = null == resolvers
|
Expression.Constant(parameter, typeof(object))),
|
||||||
? FromAttribute(parameter)
|
Expression.Rethrow(tryBlock.Type));
|
||||||
: PreProcessResolver(parameter, resolvers[i]);
|
|
||||||
|
|
||||||
// TODO: Add diagnostic for parameters
|
return Expression.TryCatch(tryBlock,
|
||||||
|
Expression.Catch(ExceptionExpr, catchBlock));
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,55 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Unity
|
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;
|
// Check if has default value
|
||||||
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
|
|
||||||
#if NET40
|
#if NET40
|
||||||
var defaultValueExpr = parameter.DefaultValue is DBNull
|
var defaultValueExpr = parameter.DefaultValue is DBNull
|
||||||
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (parameter.DefaultValue is DBNull)
|
if (parameter.DefaultValue is DBNull)
|
||||||
#else
|
#else
|
||||||
var defaultValueExpr = parameterInfo.HasDefaultValue
|
var defaultValueExpr = parameter.HasDefaultValue
|
||||||
? Expression.Constant(parameterInfo.DefaultValue, parameterInfo.ParameterType)
|
? Expression.Constant(parameter.DefaultValue, parameter.ParameterType)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!parameterInfo.HasDefaultValue)
|
if (!parameter.HasDefaultValue)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// Plain vanilla case
|
// Plain vanilla case
|
||||||
yield return Expression.Assign(parameterExpr, Expression.Convert(
|
return Expression.Assign(expression, Expression.Convert(
|
||||||
Expression.Call(PipelineContextExpression.Context,
|
Expression.Call(PipelineContextExpression.Context,
|
||||||
PipelineContextExpression.ResolveParameterMethod,
|
PipelineContextExpression.ResolveParameterMethod,
|
||||||
Expression.Constant(parameterInfo, typeof(ParameterInfo)),
|
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||||
Expression.Constant(resolver, typeof(object))),
|
Expression.Constant(resolver, typeof(object))),
|
||||||
parameterInfo.ParameterType));
|
parameter.ParameterType));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var resolve = Expression.Convert(
|
var resolve = Expression.Convert(
|
||||||
Expression.Call(PipelineContextExpression.Context,
|
Expression.Call(PipelineContextExpression.Context,
|
||||||
PipelineContextExpression.ResolveParameterMethod,
|
PipelineContextExpression.ResolveParameterMethod,
|
||||||
Expression.Constant(parameterInfo, typeof(ParameterInfo)),
|
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||||
Expression.Constant(resolver, typeof(object))),
|
Expression.Constant(resolver, typeof(object))),
|
||||||
parameterInfo.ParameterType);
|
parameter.ParameterType);
|
||||||
|
|
||||||
yield return Expression.TryCatch(
|
return Expression.TryCatch(
|
||||||
Expression.Assign(parameterExpr, resolve),
|
Expression.Assign(expression, resolve),
|
||||||
Expression.Catch(typeof(Exception),
|
Expression.Catch(typeof(Exception),
|
||||||
Expression.Assign(parameterExpr, defaultValueExpr)));
|
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.Collections.Generic;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Unity;
|
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Resolution;
|
using Unity.Resolution;
|
||||||
|
@ -74,20 +73,10 @@ namespace Unity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Expression GetResolverExpression(PropertyInfo property, object? resolver)
|
#endregion
|
||||||
{
|
|
||||||
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));
|
|
||||||
|
|
||||||
return Expression.TryCatch(base.GetResolverExpression(property, resolver),
|
|
||||||
Expression.Catch(ex, block));
|
#region Resolution
|
||||||
}
|
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
||||||
{
|
{
|
||||||
|
@ -112,5 +101,22 @@ namespace Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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
|
#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
|
#region Resolution
|
||||||
|
|
||||||
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
protected override ResolveDelegate<PipelineContext> GetResolverDelegate(PropertyInfo info, object? resolver)
|
||||||
|
@ -78,5 +61,22 @@ namespace Unity
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#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();
|
var builder = new StringBuilder();
|
||||||
builder.AppendLine(ex.Message);
|
builder.AppendLine(ex.Message);
|
||||||
builder.AppendLine(line);
|
builder.AppendLine(line);
|
||||||
builder.AppendLine("Exception occurred while:");
|
builder.AppendLine("Exception occurred:");
|
||||||
|
|
||||||
foreach (DictionaryEntry item in ex.Data)
|
foreach (DictionaryEntry item in ex.Data)
|
||||||
builder.AppendLine(DataToString(item.Value));
|
builder.AppendLine(DataToString(item.Value));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче