Moved to delegate factory for resolver
This commit is contained in:
Родитель
cf55bd92ea
Коммит
d10edf57cc
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
@ -24,8 +25,58 @@ namespace Unity.Builder
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IResolveContext
|
||||||
|
|
||||||
|
public IUnityContainer Container => Lifetime?.Container;
|
||||||
|
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
public string Name => RegistrationName;
|
||||||
|
|
||||||
|
public object Resolve(Type type, string name) => Resolve(type, name,
|
||||||
|
(InternalRegistration)((UnityContainer)Container).GetRegistration(type, name));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicyList
|
||||||
|
|
||||||
|
public object Get(Type type, string name, Type policyInterface)
|
||||||
|
{
|
||||||
|
return list.Get(type, name, policyInterface) ??
|
||||||
|
(type != RegistrationType || name != RegistrationName
|
||||||
|
? ((UnityContainer)Container).GetPolicy(type, name, policyInterface)
|
||||||
|
: Registration.Get(policyInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(Type type, string name, Type policyInterface, object policy)
|
||||||
|
{
|
||||||
|
list.Set(type, name, policyInterface, policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(Type type, string name, Type policyInterface)
|
||||||
|
{
|
||||||
|
list.Clear(type, name, policyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Registration
|
||||||
|
|
||||||
|
public Type RegistrationType { get; set; }
|
||||||
|
|
||||||
|
public string RegistrationName { get; set; }
|
||||||
|
|
||||||
|
public IPolicySet Registration { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Public Members
|
#region Public Members
|
||||||
|
|
||||||
|
public object Existing { get; set; }
|
||||||
|
|
||||||
public ILifetimeContainer Lifetime;
|
public ILifetimeContainer Lifetime;
|
||||||
|
|
||||||
public SynchronizedLifetimeManager RequiresRecovery;
|
public SynchronizedLifetimeManager RequiresRecovery;
|
||||||
|
@ -34,17 +85,12 @@ namespace Unity.Builder
|
||||||
|
|
||||||
public Type DeclaringType { get; private set; }
|
public Type DeclaringType { get; private set; }
|
||||||
|
|
||||||
|
public ParameterExpression Variable;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region ResolveContext
|
#region Public Methods
|
||||||
|
|
||||||
public IUnityContainer Container => Lifetime?.Container;
|
|
||||||
|
|
||||||
public object Existing { get; set; }
|
|
||||||
|
|
||||||
public object Resolve(Type type, string name) => Resolve(type, name,
|
|
||||||
(InternalRegistration)((UnityContainer)Container).GetRegistration(type, name));
|
|
||||||
|
|
||||||
public object Resolve(Type type, string name, InternalRegistration registration)
|
public object Resolve(Type type, string name, InternalRegistration registration)
|
||||||
{
|
{
|
||||||
|
@ -64,6 +110,63 @@ namespace Unity.Builder
|
||||||
return registration.BuildChain.ExecuteReThrowingPlan(ref context);
|
return registration.BuildChain.ExecuteReThrowingPlan(ref context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Resolve(ParameterInfo parameter, string name, object value)
|
||||||
|
{
|
||||||
|
var context = this;
|
||||||
|
|
||||||
|
// Process overrides if any
|
||||||
|
if (null != Overrides)
|
||||||
|
{
|
||||||
|
// Check if this parameter is overridden
|
||||||
|
for (var index = Overrides.Length - 1; index >= 0; --index)
|
||||||
|
{
|
||||||
|
var resolverOverride = Overrides[index];
|
||||||
|
|
||||||
|
// If matches with current parameter
|
||||||
|
if (resolverOverride is IEquatable<ParameterInfo> comparer && comparer.Equals(parameter))
|
||||||
|
{
|
||||||
|
// Check if itself is a value
|
||||||
|
if (resolverOverride is IResolve resolverPolicy)
|
||||||
|
{
|
||||||
|
return resolverPolicy.Resolve(ref context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to create value
|
||||||
|
var resolveDelegate = resolverOverride.GetResolver<BuilderContext>(parameter.ParameterType);
|
||||||
|
if (null != resolveDelegate)
|
||||||
|
{
|
||||||
|
return resolveDelegate(ref context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve from injectors
|
||||||
|
// TODO: Optimize via overrides
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case ResolveDelegate<BuilderContext> resolver:
|
||||||
|
return resolver(ref context);
|
||||||
|
|
||||||
|
case IResolve policy:
|
||||||
|
return policy.Resolve(ref context);
|
||||||
|
|
||||||
|
case IResolverFactory factory:
|
||||||
|
var method = factory.GetResolver<BuilderContext>(Type);
|
||||||
|
return method?.Invoke(ref context);
|
||||||
|
|
||||||
|
case Type type: // TODO: Requires evaluation
|
||||||
|
if (typeof(Type) == parameter.ParameterType) return type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case object obj:
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve from container
|
||||||
|
return Resolve(parameter.ParameterType, name);
|
||||||
|
}
|
||||||
|
|
||||||
public object Resolve(FieldInfo field, string name, object value)
|
public object Resolve(FieldInfo field, string name, object value)
|
||||||
{
|
{
|
||||||
var context = this;
|
var context = this;
|
||||||
|
@ -174,101 +277,6 @@ namespace Unity.Builder
|
||||||
return Resolve(property.PropertyType, name);
|
return Resolve(property.PropertyType, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Resolve(ParameterInfo parameter, string name, object value)
|
|
||||||
{
|
|
||||||
var context = this;
|
|
||||||
|
|
||||||
// Process overrides if any
|
|
||||||
if (null != Overrides)
|
|
||||||
{
|
|
||||||
// Check if this parameter is overridden
|
|
||||||
for (var index = Overrides.Length - 1; index >= 0; --index)
|
|
||||||
{
|
|
||||||
var resolverOverride = Overrides[index];
|
|
||||||
|
|
||||||
// If matches with current parameter
|
|
||||||
if (resolverOverride is IEquatable<ParameterInfo> comparer && comparer.Equals(parameter))
|
|
||||||
{
|
|
||||||
// Check if itself is a value
|
|
||||||
if (resolverOverride is IResolve resolverPolicy)
|
|
||||||
{
|
|
||||||
return resolverPolicy.Resolve(ref context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to create value
|
|
||||||
var resolveDelegate = resolverOverride.GetResolver<BuilderContext>(parameter.ParameterType);
|
|
||||||
if (null != resolveDelegate)
|
|
||||||
{
|
|
||||||
return resolveDelegate(ref context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve from injectors
|
|
||||||
// TODO: Optimize via overrides
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case ResolveDelegate<BuilderContext> resolver:
|
|
||||||
return resolver(ref context);
|
|
||||||
|
|
||||||
case IResolve policy:
|
|
||||||
return policy.Resolve(ref context);
|
|
||||||
|
|
||||||
case IResolverFactory factory:
|
|
||||||
var method = factory.GetResolver<BuilderContext>(Type);
|
|
||||||
return method?.Invoke(ref context);
|
|
||||||
|
|
||||||
case Type type: // TODO: Requires evaluation
|
|
||||||
if (typeof(Type) == parameter.ParameterType) return type;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case object obj:
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve from container
|
|
||||||
return Resolve(parameter.ParameterType, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Registration
|
|
||||||
|
|
||||||
public Type RegistrationType { get; set; }
|
|
||||||
|
|
||||||
public string RegistrationName { get; set; }
|
|
||||||
|
|
||||||
public IPolicySet Registration { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Build
|
|
||||||
|
|
||||||
public Type Type { get; set; }
|
|
||||||
|
|
||||||
public string Name => RegistrationName;
|
|
||||||
|
|
||||||
public object Get(Type type, string name, Type policyInterface)
|
|
||||||
{
|
|
||||||
return list.Get(type, name, policyInterface) ??
|
|
||||||
(type != RegistrationType || name != RegistrationName
|
|
||||||
? ((UnityContainer)Container).GetPolicy(type, name, policyInterface)
|
|
||||||
: Registration.Get(policyInterface));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(Type type, string name, Type policyInterface, object policy)
|
|
||||||
{
|
|
||||||
list.Set(type, name, policyInterface, policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(Type type, string name, Type policyInterface)
|
|
||||||
{
|
|
||||||
list.Clear(type, name, policyInterface);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Unity.Container.Lifetime;
|
||||||
using Unity.Resolution;
|
using Unity.Resolution;
|
||||||
using Unity.ResolverPolicy;
|
using Unity.ResolverPolicy;
|
||||||
|
|
||||||
|
@ -11,6 +13,45 @@ namespace Unity.Builder.Expressions
|
||||||
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
|
[SuppressMessage("ReSharper", "StaticMemberInGenericType")]
|
||||||
public class BuilderContextExpression : IResolveContextExpression<BuilderContext>
|
public class BuilderContextExpression : IResolveContextExpression<BuilderContext>
|
||||||
{
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private static ConstructorInfo _perResolveInfo = typeof(InternalPerResolveLifetimeManager)
|
||||||
|
.GetTypeInfo().DeclaredConstructors.First();
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly MethodInfo _resolveField =
|
||||||
|
typeof(BuilderContext).GetTypeInfo()
|
||||||
|
.GetDeclaredMethods(nameof(BuilderContext.Resolve))
|
||||||
|
.First(m =>
|
||||||
|
{
|
||||||
|
var parameters = m.GetParameters();
|
||||||
|
return 2 <= parameters.Length &&
|
||||||
|
typeof(FieldInfo) == parameters[0].ParameterType;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly MethodInfo _resolveProperty =
|
||||||
|
typeof(BuilderContext).GetTypeInfo()
|
||||||
|
.GetDeclaredMethods(nameof(BuilderContext.Resolve))
|
||||||
|
.First(m =>
|
||||||
|
{
|
||||||
|
var parameters = m.GetParameters();
|
||||||
|
return 2 <= parameters.Length &&
|
||||||
|
typeof(PropertyInfo) == parameters[0].ParameterType;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static readonly MethodInfo _resolveParameter =
|
||||||
|
typeof(BuilderContext).GetTypeInfo()
|
||||||
|
.GetDeclaredMethods(nameof(BuilderContext.Resolve))
|
||||||
|
.First(m =>
|
||||||
|
{
|
||||||
|
var parameters = m.GetParameters();
|
||||||
|
return 2 <= parameters.Length &&
|
||||||
|
typeof(ParameterInfo) == parameters[0].ParameterType;
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
#region Constructor
|
||||||
|
|
||||||
static BuilderContextExpression()
|
static BuilderContextExpression()
|
||||||
|
@ -33,6 +74,36 @@ namespace Unity.Builder.Expressions
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
public static Expression Resolve(FieldInfo field, string name, object value = null)
|
||||||
|
{
|
||||||
|
return Expression.Convert(
|
||||||
|
Expression.Call(Context, _resolveField,
|
||||||
|
Expression.Constant(field, typeof(FieldInfo)),
|
||||||
|
Expression.Constant(name, typeof(string)),
|
||||||
|
Expression.Constant(value, typeof(object))),
|
||||||
|
field.FieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression Resolve(PropertyInfo property, string name, object value = null)
|
||||||
|
{
|
||||||
|
return Expression.Convert(
|
||||||
|
Expression.Call(Context, _resolveProperty,
|
||||||
|
Expression.Constant(property, typeof(PropertyInfo)),
|
||||||
|
Expression.Constant(name, typeof(string)),
|
||||||
|
Expression.Constant(value, typeof(object))),
|
||||||
|
property.PropertyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression Resolve(ParameterInfo parameter, string name, object value = null)
|
||||||
|
{
|
||||||
|
return Expression.Convert(
|
||||||
|
Expression.Call(Context, _resolveParameter,
|
||||||
|
Expression.Constant(parameter, typeof(ParameterInfo)),
|
||||||
|
Expression.Constant(name, typeof(string)),
|
||||||
|
Expression.Constant(value, typeof(object))),
|
||||||
|
parameter.ParameterType);
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<Expression> GetParameters(MethodBase methodBase)
|
public static IEnumerable<Expression> GetParameters(MethodBase methodBase)
|
||||||
{
|
{
|
||||||
foreach (var parameter in methodBase.GetParameters())
|
foreach (var parameter in methodBase.GetParameters())
|
||||||
|
@ -68,6 +139,12 @@ namespace Unity.Builder.Expressions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Expression SetPerBuildSingleton(ref BuilderContext context)
|
||||||
|
{
|
||||||
|
return Set(context.RegistrationType, context.RegistrationName, typeof(LifetimeManager),
|
||||||
|
Expression.New(_perResolveInfo, context.Variable));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
using System;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Resolution;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
|
||||||
{
|
|
||||||
public class DynamicMethodBuildPlan : IBuildPlanPolicy, IResolve
|
|
||||||
{
|
|
||||||
private readonly Delegate _buildMethod;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buildMethod"></param>
|
|
||||||
public DynamicMethodBuildPlan(Delegate buildMethod)
|
|
||||||
{
|
|
||||||
_buildMethod = buildMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
public void BuildUp(ref BuilderContext context)
|
|
||||||
{
|
|
||||||
context.Existing = ((ResolveDelegate<BuilderContext>)_buildMethod).Invoke(ref context);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Resolve<TContext>(ref TContext context)
|
|
||||||
where TContext : IResolveContext
|
|
||||||
{
|
|
||||||
return ((ResolveDelegate<TContext>)_buildMethod).Invoke(ref context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
using System;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Storage;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An <see cref="IBuildPlanCreatorPolicy"/> implementation
|
|
||||||
/// that constructs a build plan via dynamic IL emission.
|
|
||||||
/// </summary>
|
|
||||||
public class DynamicMethodBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
|
||||||
{
|
|
||||||
private BuilderStrategy[] _strategies;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Construct a <see cref="DynamicMethodBuildPlanCreatorPolicy"/> that
|
|
||||||
/// uses the given strategy chain to construct the build plan.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="strategies">The strategy chain.</param>
|
|
||||||
public DynamicMethodBuildPlanCreatorPolicy(StagedStrategyChain<BuilderStrategy, BuilderStage> strategies)
|
|
||||||
{
|
|
||||||
strategies.Invalidated += (s, e) => _strategies = strategies.ToArray();
|
|
||||||
_strategies = strategies.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Construct a build plan.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The current build context.</param>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <returns>The created build plan.</returns>
|
|
||||||
public IBuildPlanPolicy CreatePlan(ref BuilderContext context, Type type, string name)
|
|
||||||
{
|
|
||||||
var generatorContext = new DynamicBuildPlanGenerationContext(type);
|
|
||||||
|
|
||||||
var planContext = new BuilderContext
|
|
||||||
{
|
|
||||||
Existing = generatorContext,
|
|
||||||
Lifetime = context.Lifetime,
|
|
||||||
RegistrationType = context.RegistrationType,
|
|
||||||
RegistrationName = context.RegistrationName,
|
|
||||||
Registration = context.Registration,
|
|
||||||
Type = context.Type,
|
|
||||||
|
|
||||||
list = context.list
|
|
||||||
};
|
|
||||||
|
|
||||||
var plan = _strategies.ExecutePlan(ref planContext);
|
|
||||||
|
|
||||||
return new DynamicMethodBuildPlan(generatorContext.GetBuildMethod());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,10 +3,7 @@ using Unity.Builder;
|
||||||
|
|
||||||
namespace Unity.Policy
|
namespace Unity.Policy
|
||||||
{
|
{
|
||||||
/// <summary>
|
[Obsolete("This interface has been replaced with Unity.Policy.ResolveDelegateFactory delegate", true)]
|
||||||
/// A policy that can create and return an <see cref="IBuildPlanPolicy"/>
|
|
||||||
/// for the given build key.
|
|
||||||
/// </summary>
|
|
||||||
public interface IBuildPlanCreatorPolicy
|
public interface IBuildPlanCreatorPolicy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
|
@ -2,15 +2,14 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Container.Lifetime;
|
using Unity.Container.Lifetime;
|
||||||
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
|
||||||
|
|
||||||
namespace Unity.Policy.BuildPlanCreator
|
namespace Unity.Policy.BuildPlanCreator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IBuildPlanCreatorPolicy"/> implementation
|
/// An <see cref="IResolveDelegateFactory"/> implementation
|
||||||
/// that constructs a build plan for creating <see cref="Lazy{T}"/> objects.
|
/// that constructs a build plan for creating <see cref="Lazy{T}"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericLazyBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
public class GenericLazyBuildPlanCreatorPolicy
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
|
@ -21,14 +20,14 @@ namespace Unity.Policy.BuildPlanCreator
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region IBuildPlanCreatorPolicy
|
#region IResolveDelegateFactory
|
||||||
|
|
||||||
public IBuildPlanPolicy CreatePlan(ref BuilderContext context, Type type, string name)
|
public static ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context)
|
||||||
{
|
{
|
||||||
var itemType = context.Type.GetTypeInfo().GenericTypeArguments[0];
|
var itemType = context.Type.GetTypeInfo().GenericTypeArguments[0];
|
||||||
var lazyMethod = BuildResolveLazyMethod.MakeGenericMethod(itemType);
|
var lazyMethod = BuildResolveLazyMethod.MakeGenericMethod(itemType);
|
||||||
|
|
||||||
return new DynamicMethodBuildPlan(lazyMethod.CreateDelegate(typeof(ResolveDelegate<BuilderContext>)));
|
return (ResolveDelegate<BuilderContext>)lazyMethod.CreateDelegate(typeof(ResolveDelegate<BuilderContext>));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
using Unity.Builder;
|
||||||
|
|
||||||
|
namespace Unity.Policy
|
||||||
|
{
|
||||||
|
public delegate ResolveDelegate<BuilderContext> ResolveDelegateFactory(ref BuilderContext context);
|
||||||
|
|
||||||
|
public interface IResolveDelegateFactory
|
||||||
|
{
|
||||||
|
ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,28 +42,39 @@ namespace Unity.Strategies
|
||||||
var resolver = context.Registration.Get<ResolveDelegate<BuilderContext>>();
|
var resolver = context.Registration.Get<ResolveDelegate<BuilderContext>>();
|
||||||
if (null == resolver)
|
if (null == resolver)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Legacy support
|
// Legacy support
|
||||||
// TODO: Verify and optimize getting default
|
// TODO: Verify and optimize getting default
|
||||||
var plan = context.Registration.Get<IBuildPlanPolicy>() ??
|
var plan = context.Registration.Get<IBuildPlanPolicy>() ??
|
||||||
(IBuildPlanPolicy)(
|
(IBuildPlanPolicy)(
|
||||||
context.Get(context.Type, string.Empty, typeof(IBuildPlanPolicy)) ??
|
context.Get(context.Type, string.Empty, typeof(IBuildPlanPolicy)) ??
|
||||||
GetGeneric(ref context, typeof(IBuildPlanPolicy),
|
GetGeneric(ref context, typeof(IBuildPlanPolicy), context.RegistrationType, context.RegistrationName));
|
||||||
context.RegistrationType, context.RegistrationName));
|
|
||||||
|
|
||||||
if (plan == null || plan is OverriddenBuildPlanMarkerPolicy)
|
if (plan == null)
|
||||||
{
|
{
|
||||||
var planCreator = context.Registration.Get<IBuildPlanCreatorPolicy>() ??
|
// Check if can create
|
||||||
CheckIfOpenGeneric(context.RegistrationType, context.Registration) ??
|
#if NETCOREAPP1_0 || NETSTANDARD1_0
|
||||||
Get_Policy<IBuildPlanCreatorPolicy>(ref context, context.Type, context.Name);
|
if (!(context.Registration is ContainerRegistration) && context.RegistrationType.GetTypeInfo().IsGenericTypeDefinition)
|
||||||
|
#else
|
||||||
if (planCreator != null)
|
if (!(context.Registration is ContainerRegistration) && context.RegistrationType.IsGenericTypeDefinition)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
plan = planCreator.CreatePlan(ref context, context.Type, context.Name);
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Constants.CannotResolveOpenGenericType, context.RegistrationType.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
if (plan is IResolve policy)
|
// Create plan
|
||||||
context.Registration.Set(typeof(ResolveDelegate<BuilderContext>), (ResolveDelegate<BuilderContext>)policy.Resolve);
|
var factory = context.Registration.Get<ResolveDelegateFactory>() ??
|
||||||
else
|
Get_Policy<ResolveDelegateFactory>(ref context, context.Type, context.Name);
|
||||||
context.Registration.Set(typeof(IBuildPlanPolicy), plan);
|
|
||||||
|
if (null != factory)
|
||||||
|
{
|
||||||
|
resolver = factory(ref context);
|
||||||
|
|
||||||
|
context.Registration.Set(typeof(ResolveDelegate<BuilderContext>), resolver);
|
||||||
|
context.Existing = resolver(ref context);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ResolutionFailedException(context.Type, context.Name, "Failed to find Build Plan Creator Policy");
|
throw new ResolutionFailedException(context.Type, context.Name, "Failed to find Build Plan Creator Policy");
|
||||||
|
@ -105,22 +116,6 @@ namespace Unity.Strategies
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static IBuildPlanCreatorPolicy CheckIfOpenGeneric(Type type, IPolicySet namedType)
|
|
||||||
{
|
|
||||||
if (namedType is InternalRegistration registration && !(namedType is ContainerRegistration) &&
|
|
||||||
#if NETCOREAPP1_0 || NETSTANDARD1_0
|
|
||||||
type.GetTypeInfo().IsGenericTypeDefinition)
|
|
||||||
#else
|
|
||||||
type.IsGenericTypeDefinition)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
|
||||||
Constants.CannotResolveOpenGenericType, type.FullName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ using Unity.Builder.Strategies;
|
||||||
using Unity.Container.Lifetime;
|
using Unity.Container.Lifetime;
|
||||||
using Unity.Events;
|
using Unity.Events;
|
||||||
using Unity.Extension;
|
using Unity.Extension;
|
||||||
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
using Unity.Policy.BuildPlanCreator;
|
using Unity.Policy.BuildPlanCreator;
|
||||||
using Unity.Registration;
|
using Unity.Registration;
|
||||||
|
@ -133,7 +132,7 @@ namespace Unity
|
||||||
Set(null, null, GetDefaultPolicies());
|
Set(null, null, GetDefaultPolicies());
|
||||||
Set(typeof(Func<>), string.Empty, typeof(LifetimeManager), new PerResolveLifetimeManager());
|
Set(typeof(Func<>), string.Empty, typeof(LifetimeManager), new PerResolveLifetimeManager());
|
||||||
Set(typeof(Func<>), string.Empty, typeof(IBuildPlanPolicy), new DeferredResolveCreatorPolicy());
|
Set(typeof(Func<>), string.Empty, typeof(IBuildPlanPolicy), new DeferredResolveCreatorPolicy());
|
||||||
Set(typeof(Lazy<>), string.Empty, typeof(IBuildPlanCreatorPolicy), new GenericLazyBuildPlanCreatorPolicy());
|
Set(typeof(Lazy<>), string.Empty, typeof(ResolveDelegateFactory), (ResolveDelegateFactory)GenericLazyBuildPlanCreatorPolicy.GetResolver);
|
||||||
|
|
||||||
// Register this instance
|
// Register this instance
|
||||||
((IUnityContainer)this).RegisterInstance(typeof(IUnityContainer), null, this, new ContainerLifetimeManager());
|
((IUnityContainer)this).RegisterInstance(typeof(IUnityContainer), null, this, new ContainerLifetimeManager());
|
||||||
|
@ -187,7 +186,7 @@ namespace Unity
|
||||||
{
|
{
|
||||||
var defaults = new InternalRegistration(null, null);
|
var defaults = new InternalRegistration(null, null);
|
||||||
|
|
||||||
defaults.Set(typeof(IBuildPlanCreatorPolicy), new DynamicMethodBuildPlanCreatorPolicy(_buildPlanStrategies));
|
defaults.Set(typeof(ResolveDelegateFactory), (ResolveDelegateFactory)GetResolver);
|
||||||
defaults.Set(typeof(IConstructorSelectorPolicy), new DefaultUnityConstructorSelector());
|
defaults.Set(typeof(IConstructorSelectorPolicy), new DefaultUnityConstructorSelector());
|
||||||
defaults.Set(typeof(IFieldSelectorPolicy), new DefaultUnityFieldsSelector());
|
defaults.Set(typeof(IFieldSelectorPolicy), new DefaultUnityFieldsSelector());
|
||||||
defaults.Set(typeof(IPropertySelectorPolicy), new DefaultUnityPropertiesSelector());
|
defaults.Set(typeof(IPropertySelectorPolicy), new DefaultUnityPropertiesSelector());
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
|
using Unity.Policy;
|
||||||
using Unity.Registration;
|
using Unity.Registration;
|
||||||
using Unity.Storage;
|
using Unity.Storage;
|
||||||
|
|
||||||
|
@ -157,6 +158,55 @@ namespace Unity
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Build Plan
|
||||||
|
|
||||||
|
|
||||||
|
private ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context)
|
||||||
|
{
|
||||||
|
var generatorContext = new ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanGenerationContext(context.Type);
|
||||||
|
|
||||||
|
var planContext = new BuilderContext
|
||||||
|
{
|
||||||
|
Existing = generatorContext,
|
||||||
|
Lifetime = context.Lifetime,
|
||||||
|
RegistrationType = context.RegistrationType,
|
||||||
|
RegistrationName = context.RegistrationName,
|
||||||
|
Registration = context.Registration,
|
||||||
|
Type = context.Type,
|
||||||
|
|
||||||
|
list = context.list
|
||||||
|
};
|
||||||
|
|
||||||
|
var plan = _buildPlanStrategies.ToArray().ExecutePlan(ref planContext);
|
||||||
|
|
||||||
|
return generatorContext.GetBuildMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//private ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context)
|
||||||
|
//{
|
||||||
|
// context.Variable = Expression.Variable(context.Type, "instance");
|
||||||
|
|
||||||
|
// var expressions = new List<Expression>();
|
||||||
|
|
||||||
|
// foreach (var strategy in _buildPlanStrategies.ToArray())
|
||||||
|
// {
|
||||||
|
// //foreach (var step in strategy.BuildUp(ref context))
|
||||||
|
// // expressions.Add(step);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// expressions.Add(Expression.Convert(context.Variable, typeof(object)));
|
||||||
|
|
||||||
|
// var lambda = Expression.Lambda<ResolveDelegate<BuilderContext>>(
|
||||||
|
// Expression.Block(new ParameterExpression[] { context.Variable }, expressions),
|
||||||
|
// BuilderContextExpression.Context);
|
||||||
|
|
||||||
|
// return lambda.Compile();
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Exceptions
|
#region Exceptions
|
||||||
|
|
||||||
public static string CreateMessage(Type typeRequested, string nameRequested, Exception innerException,
|
public static string CreateMessage(Type typeRequested, string nameRequested, Exception innerException,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using BenchmarkDotNet.Configs;
|
using BenchmarkDotNet.Configs;
|
||||||
using BenchmarkDotNet.Jobs;
|
using BenchmarkDotNet.Jobs;
|
||||||
using BenchmarkDotNet.Validators;
|
using BenchmarkDotNet.Validators;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Runner.Setup
|
namespace Runner.Setup
|
||||||
{
|
{
|
||||||
|
@ -9,11 +8,12 @@ namespace Runner.Setup
|
||||||
{
|
{
|
||||||
public BenchmarkConfiguration()
|
public BenchmarkConfiguration()
|
||||||
{
|
{
|
||||||
Add(JitOptimizationsValidator.DontFailOnError); // ALLOW NON-OPTIMIZED DLLS
|
|
||||||
|
|
||||||
Add(Job.Default
|
Add(Job.Default
|
||||||
.WithUnrollFactor(1)
|
.WithUnrollFactor(1)
|
||||||
.WithInvocationCount(50000));
|
.WithInvocationCount(1));
|
||||||
|
|
||||||
|
Add(JitOptimizationsValidator.DontFailOnError); // ALLOW NON-OPTIMIZED DLLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace Runner.Tests
|
||||||
_container.RegisterType<IService, Service>("1");
|
_container.RegisterType<IService, Service>("1");
|
||||||
_container.RegisterType<IService, Service>("2");
|
_container.RegisterType<IService, Service>("2");
|
||||||
|
|
||||||
|
_container.Resolve<object>();
|
||||||
_container.Resolve<Poco>();
|
_container.Resolve<Poco>();
|
||||||
_container.Resolve<IService>();
|
_container.Resolve<IService>();
|
||||||
_container.Resolve<IService>("1");
|
_container.Resolve<IService>("1");
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Resolution;
|
|
||||||
using Unity.ResolverPolicy;
|
|
||||||
|
|
||||||
namespace Unity.Tests.v5
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class ExpressionFixture
|
|
||||||
{
|
|
||||||
public IUnityContainer _container;
|
|
||||||
public MockContext _context = new MockContext();
|
|
||||||
|
|
||||||
[TestInitialize]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_container = new UnityContainer();
|
|
||||||
_context.Existing = null;
|
|
||||||
_context.Type = typeof(Service);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void CreateNewExpression()
|
|
||||||
{
|
|
||||||
ref var context = ref _context;
|
|
||||||
|
|
||||||
var fieldInfo = context.Type.GetField(nameof(Service.Field));
|
|
||||||
var propInfo = context.Type.GetProperty(nameof(Service.Property));
|
|
||||||
|
|
||||||
var varExpr = Expression.Variable(context.Type, "instance");
|
|
||||||
|
|
||||||
var fieldExpr = Expression.Field(varExpr, fieldInfo);
|
|
||||||
var propExpr = Expression.Property(varExpr, propInfo);
|
|
||||||
|
|
||||||
var blockExpr = Expression.Block(new ParameterExpression[] { varExpr }, new Expression[]
|
|
||||||
{
|
|
||||||
Expression.IfThenElse(Expression.NotEqual( Expression.Constant(null), BuilderContextExpression.Existing),
|
|
||||||
Expression.Assign( varExpr, Expression.Convert(BuilderContextExpression.Existing, context.Type)),
|
|
||||||
Expression.Assign( varExpr, Expression.New(typeof(Service)))),
|
|
||||||
|
|
||||||
Expression.Assign(fieldExpr, BuilderContextExpression.Resolve(fieldInfo, null, null)),
|
|
||||||
Expression.Assign(propExpr, BuilderContextExpression.Resolve(propInfo, null, null)),
|
|
||||||
|
|
||||||
varExpr
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var lambda = Expression.Lambda<ResolveDelegate<MockContext>>(blockExpr, BuilderContextExpression.Context);
|
|
||||||
var plan = lambda.Compile();
|
|
||||||
var instance = (Service)plan(ref context);
|
|
||||||
|
|
||||||
Assert.IsNotNull(instance);
|
|
||||||
Assert.AreEqual(instance.Field, Service.First);
|
|
||||||
Assert.AreEqual(instance.Property, Service.Other);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void BaselineTest()
|
|
||||||
{
|
|
||||||
ResolveDelegate<BuilderContext> plan = (ref BuilderContext context) =>
|
|
||||||
{
|
|
||||||
Service instance;
|
|
||||||
if (null == context.Existing)
|
|
||||||
{
|
|
||||||
instance = new Service();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
instance = (Service)context.Existing;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.Field = Service.First;
|
|
||||||
instance.Property = Service.Other;
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = new Service();
|
|
||||||
result.Field = Service.First;
|
|
||||||
result.Property = Service.Other;
|
|
||||||
|
|
||||||
Assert.IsNotNull(result);
|
|
||||||
Assert.AreEqual(result.Field, Service.First);
|
|
||||||
Assert.AreEqual(result.Property, Service.Other);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IService { }
|
|
||||||
public class Service : IService
|
|
||||||
{
|
|
||||||
public static string First = "name";
|
|
||||||
public static string Other = "other";
|
|
||||||
|
|
||||||
public string Field;
|
|
||||||
|
|
||||||
public string Property { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BuilderContextExpression : IResolveContextExpression<MockContext>
|
|
||||||
{
|
|
||||||
public static readonly MemberExpression Existing =
|
|
||||||
Expression.MakeMemberAccess(Context, typeof(MockContext).GetTypeInfo()
|
|
||||||
.GetDeclaredProperty(nameof(MockContext.Existing)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct MockContext : IResolveContext
|
|
||||||
{
|
|
||||||
|
|
||||||
#region ResolveContext
|
|
||||||
|
|
||||||
public IUnityContainer Container => null;
|
|
||||||
|
|
||||||
public object Existing { get; set; }
|
|
||||||
|
|
||||||
public object Resolve(Type type, string name)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Resolve(FieldInfo field, string name, object value) => Service.First;
|
|
||||||
|
|
||||||
public object Resolve(PropertyInfo property, string name, object value) => Service.Other;
|
|
||||||
|
|
||||||
public object Resolve(ParameterInfo parameter, string name, object value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Build
|
|
||||||
|
|
||||||
public Type Type { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public object Get(Type type, string name, Type policyInterface)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(Type type, string name, Type policyInterface, object policy)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(Type type, string name, Type policyInterface)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Загрузка…
Ссылка в новой задаче