This commit is contained in:
Eugene Sadovoi 2018-12-27 12:38:26 -05:00
Родитель 92285ea874
Коммит b6f43256bf
25 изменённых файлов: 279 добавлений и 611 удалений

Просмотреть файл

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Policy;
using Unity.Storage;
using Unity.Strategies;
namespace Unity.Builder
{
public class CompiledStrategy<TMemberInfo, TData> : BuilderStrategy,
IStagedStrategyChain<Converter<Type, (TMemberInfo, TData)>, SelectionStage>
where TMemberInfo : MemberInfo
{
#region Fields
private readonly List<Converter<Type, (TMemberInfo, TData)>>[] _stages;
private Converter<Type, (TMemberInfo, TData)>[] _cache;
#endregion
#region Constructors
public CompiledStrategy(params (Converter<Type, (TMemberInfo, TData)>, SelectionStage)[] arguments)
{
var length = Enum.GetValues(typeof(SelectionStage)).Length;
_stages = new List<Converter<Type, (TMemberInfo, TData)>>[length];
for (var i = 0; i < length; i++)
{
_stages[i] = new List<Converter<Type, (TMemberInfo, TData)>>();
}
foreach (var tuple in arguments)
{
_stages[Convert.ToInt32(tuple.Item2)].Add(tuple.Item1);
}
_cache = _stages.SelectMany(s => s).ToArray();
}
#endregion
#region IStagedStrategyChain
public void Add(Converter<Type, (TMemberInfo, TData)> strategy, SelectionStage stage)
{
lock (_stages)
{
_stages[Convert.ToInt32(stage)].Add(strategy);
_cache = _stages.SelectMany(s => s).ToArray();
Invalidated?.Invoke(this, new EventArgs());
}
}
#endregion
#region Event
public event EventHandler<EventArgs> Invalidated;
#endregion
}
}

Просмотреть файл

@ -1,12 +1,12 @@
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;
using Unity.Registration; using Unity.Registration;
using Unity.Resolution; using Unity.Resolution;
using Unity.Storage; using Unity.Storage;
using Unity.Strategies;
namespace Unity.Builder namespace Unity.Builder
{ {
@ -73,7 +73,7 @@ namespace Unity.Builder
#endregion #endregion
#region Public Members #region Public Properties
public object Existing { get; set; } public object Existing { get; set; }
@ -85,8 +85,6 @@ namespace Unity.Builder
public Type DeclaringType { get; private set; } public Type DeclaringType { get; private set; }
public ParameterExpression Variable;
#endregion #endregion
@ -107,7 +105,7 @@ namespace Unity.Builder
DeclaringType = RegistrationType DeclaringType = RegistrationType
}; };
return registration.BuildChain.ExecuteReThrowingPlan(ref context); return ExecuteReThrowingPlan(registration.BuildChain, ref context);
} }
public object Resolve(ParameterInfo parameter, string name, object value) public object Resolve(ParameterInfo parameter, string name, object value)
@ -278,5 +276,36 @@ namespace Unity.Builder
} }
#endregion #endregion
#region Implementation
private static object ExecuteReThrowingPlan(BuilderStrategy[] chain, ref BuilderContext context)
{
var i = -1;
try
{
while (!context.BuildComplete && ++i < chain.Length)
{
chain[i].PreBuildUp(ref context);
}
while (--i >= 0)
{
chain[i].PostBuildUp(ref context);
}
}
catch
{
context.RequiresRecovery?.Recover();
throw;
}
return context.Existing;
}
#endregion
} }
} }

Просмотреть файл

@ -0,0 +1,29 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Resolution;
namespace Unity.Builder
{
public class BuilderContextExpression : IResolveContextExpression<BuilderContext>
{
#region Constructor
static BuilderContextExpression()
{
var typeInfo = typeof(BuilderContext).GetTypeInfo();
Existing = Expression.MakeMemberAccess(Context, typeInfo.GetDeclaredProperty(nameof(BuilderContext.Existing)));
}
#endregion
#region Public Properties
public static readonly MemberExpression Existing;
#endregion
}
}

Просмотреть файл

@ -1,110 +0,0 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Container.Lifetime;
using Unity.Resolution;
namespace Unity.Builder.Expressions
{
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
static BuilderContextExpression()
{
var typeInfo = typeof(BuilderContext).GetTypeInfo();
Existing = Expression.MakeMemberAccess(Context, typeInfo.GetDeclaredProperty(nameof(BuilderContext.Existing)));
}
#endregion
#region Public Properties
public static readonly MemberExpression Existing;
#endregion
#region Methods
public static Expression Resolve(FieldInfo field, string name, object resolver = null)
{
return Expression.Convert(
Expression.Call(Context, _resolveField,
Expression.Constant(field, typeof(FieldInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
field.FieldType);
}
public static Expression Resolve(PropertyInfo property, string name, object resolver = null)
{
return Expression.Convert(
Expression.Call(Context, _resolveProperty,
Expression.Constant(property, typeof(PropertyInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
property.PropertyType);
}
public static Expression Resolve(ParameterInfo parameter, string name, object resolver = null)
{
return Expression.Convert(
Expression.Call(Context, _resolveParameter,
Expression.Constant(parameter, typeof(ParameterInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
parameter.ParameterType);
}
public static Expression SetPerBuildSingleton(ref BuilderContext context)
{
return Set(context.RegistrationType, context.RegistrationName, typeof(LifetimeManager),
Expression.New(_perResolveInfo, context.Variable));
}
#endregion
}
}

Просмотреть файл

@ -1,21 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
namespace Unity.Builder.Expressions
{
public class ExceptionExpression
{
public static readonly ConstructorInfo InvalidOperationExceptionCtor =
typeof(InvalidOperationException)
.GetTypeInfo()
.DeclaredConstructors
.First(c =>
{
var parameters = c.GetParameters();
return 2 == parameters.Length &&
typeof(string) == parameters[0].ParameterType &&
typeof(Exception) == parameters[1].ParameterType;
});
}
}

Просмотреть файл

@ -1,78 +0,0 @@
using System;
using Unity.Strategies;
namespace Unity.Builder
{
public static class PlanExtension
{
public static object ExecutePlan(this BuilderStrategy[] chain, ref BuilderContext context)
{
var i = -1;
while (!context.BuildComplete && ++i < chain.Length)
{
chain[i].PreBuildUp(ref context);
}
while (--i >= 0)
{
chain[i].PostBuildUp(ref context);
}
return context.Existing;
}
public static object ExecuteThrowingPlan(this BuilderStrategy[] chain, ref BuilderContext context)
{
var i = -1;
try
{
while (!context.BuildComplete && ++i < chain.Length)
{
chain[i].PreBuildUp(ref context);
}
while (--i >= 0)
{
chain[i].PostBuildUp(ref context);
}
}
catch (Exception ex)
{
context.RequiresRecovery?.Recover();
// TODO: 5.9.0 Add proper error message
throw new ResolutionFailedException(context.RegistrationType,
context.RegistrationName,
"", ex);
}
return context.Existing;
}
public static object ExecuteReThrowingPlan(this BuilderStrategy[] chain, ref BuilderContext context)
{
var i = -1;
try
{
while (!context.BuildComplete && ++i < chain.Length)
{
chain[i].PreBuildUp(ref context);
}
while (--i >= 0)
{
chain[i].PostBuildUp(ref context);
}
}
catch
{
context.RequiresRecovery?.Recover();
throw;
}
return context.Existing;
}
}
}

Просмотреть файл

@ -4,9 +4,7 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Unity.Builder; using Unity.Builder;
using Unity.Builder.Expressions;
using Unity.Policy; using Unity.Policy;
using Unity.Resolution;
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
{ {

Просмотреть файл

@ -14,7 +14,28 @@ namespace Unity.Processors
public abstract class MemberBuildProcessor public abstract class MemberBuildProcessor
{ {
#region Fields
protected static readonly MethodInfo StringFormat =
typeof(string).GetTypeInfo()
.DeclaredMethods
.First(m =>
{
var parameters = m.GetParameters();
return m.Name == nameof(string.Format) &&
m.GetParameters().Length == 2 &&
typeof(object) == parameters[1].ParameterType;
});
protected static readonly Expression InvalidRegistrationExpression = Expression.New(typeof(InvalidRegistrationException));
#endregion
#region Public Methods
public abstract IEnumerable<Expression> GetEnumerator(ref BuilderContext context); public abstract IEnumerable<Expression> GetEnumerator(ref BuilderContext context);
#endregion
} }
@ -23,18 +44,6 @@ namespace Unity.Processors
{ {
#region Fields #region Fields
protected static readonly MethodInfo StringFormat =
typeof(string).GetTypeInfo()
.DeclaredMethods
.First(m =>
{
var parameters = m.GetParameters();
return m.Name == nameof(string.Format) &&
m.GetParameters().Length == 2 &&
typeof(object) == parameters[1].ParameterType;
});
protected static readonly Expression InvalidRegistrationExpression = Expression.New(typeof(InvalidRegistrationException));
protected (Type type, MemberExpressionFactory factory)[] ResolverFactories; protected (Type type, MemberExpressionFactory factory)[] ResolverFactories;
#endregion #endregion
@ -79,7 +88,7 @@ namespace Unity.Processors
#region Public Methods #region Public Methods
public virtual void Add(Type type, MemberExpressionFactory factory) public void Add(Type type, MemberExpressionFactory factory)
{ {
for (var i = 0; i < ResolverFactories.Length; i++) for (var i = 0; i < ResolverFactories.Length; i++)
{ {
@ -104,7 +113,7 @@ namespace Unity.Processors
{ {
var selector = GetPolicy<ISelect<TMemberInfo>>(ref context, context.RegistrationType, context.RegistrationName); var selector = GetPolicy<ISelect<TMemberInfo>>(ref context, context.RegistrationType, context.RegistrationName);
var members = selector.Select(ref context); var members = selector.Select(ref context);
return GetEnumerator(context.Type, context.Name, context.Variable, members); return GetEnumerator(context.Type, context.Name, members);
} }
#endregion #endregion
@ -112,7 +121,7 @@ namespace Unity.Processors
#region Expression Building #region Expression Building
protected virtual IEnumerable<Expression> GetEnumerator(Type type, string name, ParameterExpression variable, IEnumerable<object> members) protected virtual IEnumerable<Expression> GetEnumerator(Type type, string name, IEnumerable<object> members)
{ {
foreach (var member in members) foreach (var member in members)
{ {
@ -121,13 +130,13 @@ namespace Unity.Processors
switch (member) switch (member)
{ {
case TMemberInfo memberInfo: case TMemberInfo memberInfo:
memberExpr = CreateMemberExpression(variable, memberInfo); memberExpr = CreateMemberExpression(memberInfo);
yield return BuildMemberExpression(memberExpr, memberInfo, name, null); yield return BuildMemberExpression(memberExpr, memberInfo, name, null);
break; break;
case InjectionMember<TMemberInfo, TData> injectionMember: case InjectionMember<TMemberInfo, TData> injectionMember:
var (info, value) = injectionMember.FromType(type); var (info, value) = injectionMember.FromType(type);
memberExpr = CreateMemberExpression(variable, info); memberExpr = CreateMemberExpression(info);
yield return BuildMemberExpression(memberExpr, info, name, value); yield return BuildMemberExpression(memberExpr, info, name, value);
break; break;
@ -169,7 +178,7 @@ namespace Unity.Processors
protected virtual Expression ResolveExpression(TMemberInfo info, string name, object resolver) protected virtual Expression ResolveExpression(TMemberInfo info, string name, object resolver)
=> throw new NotImplementedException(); => throw new NotImplementedException();
protected virtual MemberExpression CreateMemberExpression(ParameterExpression variable, TMemberInfo info) protected virtual MemberExpression CreateMemberExpression(TMemberInfo info)
=> throw new NotImplementedException(); => throw new NotImplementedException();
#endregion #endregion

Просмотреть файл

@ -1,8 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Unity.Builder.Expressions; using Unity.Builder;
using Unity.Injection; using Unity.Injection;
namespace Unity.Processors namespace Unity.Processors
@ -10,6 +11,21 @@ namespace Unity.Processors
public abstract class MethodBaseInfoProcessor<TMemberInfo> : MemberBuildProcessor<TMemberInfo, object[]> public abstract class MethodBaseInfoProcessor<TMemberInfo> : MemberBuildProcessor<TMemberInfo, object[]>
where TMemberInfo : MethodBase where TMemberInfo : MethodBase
{ {
#region Fields
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 Constructors #region Constructors
public MethodBaseInfoProcessor(Type attribute) public MethodBaseInfoProcessor(Type attribute)
@ -27,7 +43,7 @@ namespace Unity.Processors
protected override Type MemberType(TMemberInfo info) => info.DeclaringType; protected override Type MemberType(TMemberInfo info) => info.DeclaringType;
protected override IEnumerable<Expression> GetEnumerator(Type type, string name, ParameterExpression variable, IEnumerable<object> members) protected override IEnumerable<Expression> GetEnumerator(Type type, string name, IEnumerable<object> members)
{ {
foreach (var member in members) foreach (var member in members)
{ {
@ -35,13 +51,13 @@ namespace Unity.Processors
{ {
case TMemberInfo memberInfo: case TMemberInfo memberInfo:
yield return ValidateMemberInfo(memberInfo) ?? yield return ValidateMemberInfo(memberInfo) ??
CreateExpression(memberInfo, null, variable); CreateExpression(memberInfo, null);
break; break;
case MethodBaseMember<TMemberInfo> injectionMember: case MethodBaseMember<TMemberInfo> injectionMember:
var (info, resolvers) = injectionMember.FromType(type); var (info, resolvers) = injectionMember.FromType(type);
yield return ValidateMemberInfo(info) ?? yield return ValidateMemberInfo(info) ??
CreateExpression(info, resolvers, variable); CreateExpression(info, resolvers);
break; break;
default: default:
@ -76,12 +92,12 @@ namespace Unity.Processors
if (null == defaultValueExpr) if (null == defaultValueExpr)
{ {
// Plain vanilla case // Plain vanilla case
expression = BuilderContextExpression.Resolve(parameter, null, resolver); expression = ResolveExpression(parameter, null, resolver);
} }
else else
{ {
var variable = Expression.Variable(parameter.ParameterType); var variable = Expression.Variable(parameter.ParameterType);
var resolve = BuilderContextExpression.Resolve(parameter, null, resolver); var resolve = ResolveExpression(parameter, null, resolver);
expression = Expression.Block(new[] { variable }, new Expression[] expression = Expression.Block(new[] { variable }, new Expression[]
{ {
@ -121,7 +137,7 @@ namespace Unity.Processors
if (null == member) if (null == member)
{ {
// Plain vanilla case // Plain vanilla case
return BuilderContextExpression.Resolve(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver); return ResolveExpression(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver);
} }
else else
{ {
@ -133,7 +149,7 @@ namespace Unity.Processors
Expression.TryCatch( Expression.TryCatch(
Expression.Assign( Expression.Assign(
variable, variable,
BuilderContextExpression.Resolve(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver)), ResolveExpression(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver)),
Expression.Catch(typeof(Exception), Expression.Catch(typeof(Exception),
Expression.Assign(variable, member))), Expression.Assign(variable, member))),
variable variable
@ -153,7 +169,7 @@ namespace Unity.Processors
Expression.TryCatch( Expression.TryCatch(
Expression.Assign( Expression.Assign(
variable, variable,
BuilderContextExpression.Resolve(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver)), ResolveExpression(parameter, ((DependencyResolutionAttribute)attribute).Name, resolver)),
Expression.Catch(typeof(Exception), Expression.Catch(typeof(Exception),
Expression.Assign(variable, member ?? Expression.Constant(null, parameter.ParameterType)))), Expression.Assign(variable, member ?? Expression.Constant(null, parameter.ParameterType)))),
variable variable
@ -166,7 +182,17 @@ namespace Unity.Processors
#region Implementation #region Implementation
protected abstract Expression CreateExpression(TMemberInfo info, object[] resolvers, ParameterExpression variable); private Expression ResolveExpression(ParameterInfo parameter, string name, object resolver = null)
{
return Expression.Convert(
Expression.Call(BuilderContextExpression.Context, ResolveParameter,
Expression.Constant(parameter, typeof(ParameterInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
parameter.ParameterType);
}
protected abstract Expression CreateExpression(TMemberInfo info, object[] resolvers);
protected virtual Expression ValidateMemberInfo(TMemberInfo info) => null; protected virtual Expression ValidateMemberInfo(TMemberInfo info) => null;

Просмотреть файл

@ -5,10 +5,7 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Unity.Builder; using Unity.Builder;
using Unity.Builder.Expressions;
using Unity.Container.Lifetime; using Unity.Container.Lifetime;
using Unity.Injection;
using Unity.Policy;
namespace Unity.Processors namespace Unity.Processors
{ {
@ -18,6 +15,29 @@ namespace Unity.Processors
private static readonly ConstructorLengthComparer ConstructorComparer = new ConstructorLengthComparer(); private static readonly ConstructorLengthComparer ConstructorComparer = new ConstructorLengthComparer();
private static readonly ConstructorInfo PerResolveInfo = typeof(InternalPerResolveLifetimeManager)
.GetTypeInfo().DeclaredConstructors.First();
private static readonly ConstructorInfo InvalidOperationExceptionCtor =
typeof(InvalidOperationException)
.GetTypeInfo()
.DeclaredConstructors
.First(c =>
{
var parameters = c.GetParameters();
return 2 == parameters.Length &&
typeof(string) == parameters[0].ParameterType &&
typeof(Exception) == parameters[1].ParameterType;
});
private static readonly Expression NoConstructorExceptionExpr =
Expression.Throw(
Expression.New(InvalidOperationExceptionCtor,
Expression.Call(StringFormat,
Expression.Constant("No public constructor is available for type {0}."),
BuilderContextExpression.Type),
InvalidRegistrationExpression));
#endregion #endregion
@ -97,31 +117,20 @@ namespace Unity.Processors
} }
} }
var expression = base.GetEnumerator(ref context) var newExpr = base.GetEnumerator(ref context)
.FirstOrDefault(); .FirstOrDefault() ??
switch (expression) NoConstructorExceptionExpr;
{
case NewExpression newExpression:
expression = Expression.Assign(context.Variable, newExpression);
break;
case null: var IfThenExpr = Expression.IfThen(Expression.Equal(Expression.Constant(null), BuilderContextExpression.Existing),
expression = Expression.Throw( ValidateConstructedType(ref context) ?? newExpr);
Expression.New(ExceptionExpression.InvalidOperationExceptionCtor,
Expression.Call(StringFormat,
Expression.Constant("No public constructor is available for type {0}."),
BuilderContextExpression.Type),
InvalidRegistrationExpression));
break;
}
var createExpr = Expression.IfThenElse(Expression.NotEqual(Expression.Constant(null), BuilderContextExpression.Existing),
Expression.Assign(context.Variable, Expression.Convert(BuilderContextExpression.Existing, context.Type)),
ValidateConstructedType(ref context) ?? expression);
return context.Registration.Get(typeof(LifetimeManager)) is PerResolveLifetimeManager return context.Registration.Get(typeof(LifetimeManager)) is PerResolveLifetimeManager
? new Expression[] { createExpr, BuilderContextExpression.SetPerBuildSingleton(ref context) } ? new[] { IfThenExpr, BuilderContextExpression.Set(context.RegistrationType,
: new Expression[] { createExpr }; context.RegistrationName,
typeof(LifetimeManager),
Expression.New(PerResolveInfo,
BuilderContextExpression.Existing)) }
: new Expression[] { IfThenExpr };
} }
protected override Expression ValidateMemberInfo(ConstructorInfo info) protected override Expression ValidateMemberInfo(ConstructorInfo info)
@ -129,7 +138,7 @@ namespace Unity.Processors
var parameters = info.GetParameters(); var parameters = info.GetParameters();
if (parameters.Any(pi => pi.ParameterType.IsByRef)) if (parameters.Any(pi => pi.ParameterType.IsByRef))
{ {
return Expression.Throw(Expression.New(ExceptionExpression.InvalidOperationExceptionCtor, return Expression.Throw(Expression.New(InvalidOperationExceptionCtor,
Expression.Constant(CreateErrorMessage(Constants.SelectedConstructorHasRefParameters, info.DeclaringType, info)), Expression.Constant(CreateErrorMessage(Constants.SelectedConstructorHasRefParameters, info.DeclaringType, info)),
InvalidRegistrationExpression)); InvalidRegistrationExpression));
} }
@ -148,8 +157,15 @@ namespace Unity.Processors
} }
protected override Expression CreateExpression(ConstructorInfo info, object[] resolvers, ParameterExpression variable) protected override Expression CreateExpression(ConstructorInfo info, object[] resolvers)
=> Expression.New(info, CreateParameterExpressions(info.GetParameters(), resolvers)); {
var variable = Expression.Variable(info.DeclaringType);
return Expression.Block(new[] { variable }, new Expression[]
{
Expression.Assign(variable, Expression.New(info, CreateParameterExpressions(info.GetParameters(), resolvers))),
Expression.Assign(BuilderContextExpression.Existing, Expression.Convert(variable, typeof(object)))
});
}
#endregion #endregion
@ -166,7 +182,7 @@ namespace Unity.Processors
#endif #endif
{ {
return Expression.Throw( return Expression.Throw(
Expression.New(ExceptionExpression.InvalidOperationExceptionCtor, Expression.New(InvalidOperationExceptionCtor,
Expression.Call( Expression.Call(
StringFormat, StringFormat,
Expression.Constant(Constants.CannotConstructInterface), Expression.Constant(Constants.CannotConstructInterface),
@ -181,7 +197,7 @@ namespace Unity.Processors
#endif #endif
{ {
return Expression.Throw( return Expression.Throw(
Expression.New(ExceptionExpression.InvalidOperationExceptionCtor, Expression.New(InvalidOperationExceptionCtor,
Expression.Call( Expression.Call(
StringFormat, StringFormat,
Expression.Constant(Constants.CannotConstructAbstractClass), Expression.Constant(Constants.CannotConstructAbstractClass),
@ -196,7 +212,7 @@ namespace Unity.Processors
#endif #endif
{ {
return Expression.Throw( return Expression.Throw(
Expression.New(ExceptionExpression.InvalidOperationExceptionCtor, Expression.New(InvalidOperationExceptionCtor,
Expression.Call( Expression.Call(
StringFormat, StringFormat,
Expression.Constant(Constants.CannotConstructDelegate), Expression.Constant(Constants.CannotConstructDelegate),
@ -207,7 +223,7 @@ namespace Unity.Processors
if (context.Type == typeof(string)) if (context.Type == typeof(string))
{ {
return Expression.Throw( return Expression.Throw(
Expression.New(ExceptionExpression.InvalidOperationExceptionCtor, Expression.New(InvalidOperationExceptionCtor,
Expression.Call( Expression.Call(
StringFormat, StringFormat,
Expression.Constant(Constants.TypeIsNotConstructable), Expression.Constant(Constants.TypeIsNotConstructable),

Просмотреть файл

@ -4,30 +4,51 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Unity.Builder; using Unity.Builder;
using Unity.Builder.Expressions;
namespace Unity.Processors namespace Unity.Processors
{ {
public class FieldsProcessor : MemberBuildProcessor<FieldInfo, object> public class FieldsProcessor : MemberBuildProcessor<FieldInfo, object>
{ {
#region Fields
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;
});
#endregion
#region Overrides #region Overrides
public override IEnumerable<object> Select(ref BuilderContext context) => public override IEnumerable<object> Select(ref BuilderContext context) =>
base.Select(ref context).Distinct(); base.Select(ref context).Distinct();
#endregion protected override FieldInfo[] DeclaredMembers(Type type)
{
return base.DeclaredMembers(type);
#region Implementation }
protected override Type MemberType(FieldInfo info) protected override Type MemberType(FieldInfo info)
=> info.FieldType; => info.FieldType;
protected override Expression ResolveExpression(FieldInfo info, string name, object resolver) protected override Expression ResolveExpression(FieldInfo field, string name, object resolver)
=> BuilderContextExpression.Resolve(info, name, resolver); {
return Expression.Convert(
Expression.Call(BuilderContextExpression.Context, ResolveField,
Expression.Constant(field, typeof(FieldInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
field.FieldType);
}
protected override MemberExpression CreateMemberExpression(ParameterExpression variable, FieldInfo info) protected override MemberExpression CreateMemberExpression(FieldInfo info)
=> Expression.Field(variable, info); => Expression.Field(Expression.Convert(BuilderContextExpression.Existing, info.DeclaringType), info);
#endregion #endregion

Просмотреть файл

@ -55,8 +55,9 @@ namespace Unity.Processors
return null; return null;
} }
protected override Expression CreateExpression(MethodInfo info, object[] resolvers, ParameterExpression variable) protected override Expression CreateExpression(MethodInfo info, object[] resolvers)
=> Expression.Call(variable, info, CreateParameterExpressions(info.GetParameters(), resolvers)); => Expression.Call(Expression.Convert(BuilderContextExpression.Existing, info.DeclaringType),
info, CreateParameterExpressions(info.GetParameters(), resolvers));
#endregion #endregion
} }

Просмотреть файл

@ -4,13 +4,27 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using Unity.Builder; using Unity.Builder;
using Unity.Builder.Expressions;
using Unity.Utility; using Unity.Utility;
namespace Unity.Processors namespace Unity.Processors
{ {
public class PropertiesProcessor : MemberBuildProcessor<PropertyInfo, object> public class PropertiesProcessor : MemberBuildProcessor<PropertyInfo, object>
{ {
#region Fields
public 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;
});
#endregion
#region Overrides #region Overrides
public override IEnumerable<object> Select(ref BuilderContext context) => public override IEnumerable<object> Select(ref BuilderContext context) =>
@ -41,21 +55,22 @@ namespace Unity.Processors
#endif #endif
} }
#endregion
#region Implementation
protected override Type MemberType(PropertyInfo info) protected override Type MemberType(PropertyInfo info)
=> info.PropertyType; => info.PropertyType;
protected override Expression ResolveExpression(PropertyInfo member, string name, object resolver) protected override Expression ResolveExpression(PropertyInfo property, string name, object resolver)
=> BuilderContextExpression.Resolve(member, name, resolver); {
return Expression.Convert(
Expression.Call(BuilderContextExpression.Context, ResolveProperty,
Expression.Constant(property, typeof(PropertyInfo)),
Expression.Constant(name, typeof(string)),
Expression.Constant(resolver, typeof(object))),
property.PropertyType);
}
protected override MemberExpression CreateMemberExpression(ParameterExpression variable, PropertyInfo info) protected override MemberExpression CreateMemberExpression(PropertyInfo info)
=> Expression.Property(variable, info); => Expression.Property(Expression.Convert(BuilderContextExpression.Existing, info.DeclaringType), info);
#endregion #endregion
} }
} }

Просмотреть файл

@ -1,41 +0,0 @@
using System;
using Unity.Builder;
using Unity.Policy;
using Unity.Resolution;
namespace Unity.ResolverPolicy
{
/// <summary>
/// An implementation of <see cref="IResolve"/> that
/// calls back into the build chain to build up the dependency, passing
/// a type given at compile time as its build key.
/// </summary>
public class FixedTypeResolvePolicy : IResolve
{
private readonly NamedTypeBuildKey _keyToBuild;
/// <summary>
/// Create a new instance storing the given type.
/// </summary>
/// <param name="typeToBuild">Type to resolve.</param>
public FixedTypeResolvePolicy(Type typeToBuild)
{
_keyToBuild = new NamedTypeBuildKey(typeToBuild);
}
#region IResolverPolicy Members
/// <summary>
/// GetOrDefault the value for a dependency.
/// </summary>
/// <param name="context">Current build context.</param>
/// <returns>The value for the dependency.</returns>
public object Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
return context.Resolve(_keyToBuild.Type, _keyToBuild.Name);
}
#endregion
}
}

Просмотреть файл

@ -1,35 +0,0 @@
using Unity.Policy;
using Unity.Resolution;
namespace Unity.ResolverPolicy
{
/// <summary>
/// A <see cref="IResolve"/> implementation that returns
/// the value set in the constructor.
/// </summary>
public class LiteralValueDependencyResolvePolicy : IResolve
{
private readonly object _dependencyValue;
/// <summary>
/// Create a new instance of <see cref="LiteralValueDependencyResolvePolicy"/>
/// which will return the given value when resolved.
/// </summary>
/// <param name="dependencyValue">The value to return.</param>
public LiteralValueDependencyResolvePolicy(object dependencyValue)
{
_dependencyValue = dependencyValue;
}
/// <summary>
/// GetOrDefault the value for a dependency.
/// </summary>
/// <param name="context">Current build context.</param>
/// <returns>The value for the dependency.</returns>
public object Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
return _dependencyValue;
}
}
}

Просмотреть файл

@ -1,47 +0,0 @@
using System;
using Unity.Policy;
using Unity.Resolution;
namespace Unity.ResolverPolicy
{
/// <summary>
/// An implementation of <see cref="IResolve"/> that stores a
/// type and name, and at resolution time puts them together into a
/// <see cref="NamedTypeBuildKey"/>.
/// </summary>
public class NamedTypeDependencyResolvePolicy : IResolve
{
/// <summary>
/// Create an instance of <see cref="NamedTypeDependencyResolvePolicy"/>
/// with the given type and name.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">The name (may be null).</param>
public NamedTypeDependencyResolvePolicy(Type type, string name)
{
Type = type;
Name = name;
}
/// <summary>
/// Resolve the value for a dependency.
/// </summary>
/// <param name="context">Current build context.</param>
/// <returns>The value for the dependency.</returns>
public object Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
return context.Resolve(Type, Name);
}
/// <summary>
/// The type that this resolver resolves.
/// </summary>
public Type Type { get; }
/// <summary>
/// The name that this resolver resolves.
/// </summary>
public string Name { get; }
}
}

Просмотреть файл

@ -1,77 +0,0 @@
using System;
using System.Globalization;
using System.Reflection;
using Unity.Policy;
using Unity.Resolution;
namespace Unity.ResolverPolicy
{
/// <summary>
/// A <see cref="IResolve"/> that will attempt to
/// resolve a value, and return null if it cannot rather than throwing.
/// </summary>
public class OptionalDependencyResolvePolicy : IResolve
{
/// <summary>
/// Construct a new <see cref="OptionalDependencyResolvePolicy"/> object
/// that will attempt to resolve the given name and type from the container.
/// </summary>
/// <param name="type">Type to resolve. Must be a reference type.</param>
/// <param name="name">Name to resolve with.</param>
public OptionalDependencyResolvePolicy(Type type, string name)
{
if ((type ?? throw new ArgumentNullException(nameof(type))).GetTypeInfo().IsValueType)
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture,
Constants.OptionalDependenciesMustBeReferenceTypes,
type.GetTypeInfo().Name));
}
DependencyType = type;
Name = name;
}
/// <summary>
/// Construct a new <see cref="OptionalDependencyResolvePolicy"/> object
/// that will attempt to resolve the given type from the container.
/// </summary>
/// <param name="type">Type to resolve. Must be a reference type.</param>
public OptionalDependencyResolvePolicy(Type type)
: this(type, null)
{
}
/// <summary>
/// Type this resolver will resolve.
/// </summary>
public Type DependencyType { get; }
/// <summary>
/// Name this resolver will resolve.
/// </summary>
public string Name { get; }
#region IResolverPolicy Members
/// <summary>
/// GetOrDefault the value for a dependency.
/// </summary>
/// <param name="context">Current build context.</param>
/// <returns>The value for the dependency.</returns>
public object Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
try
{
return context.Resolve(DependencyType, Name);
}
catch (Exception)
{
return null;
}
}
#endregion
}
}

Просмотреть файл

@ -167,7 +167,7 @@ namespace Unity
? containerRegistration.Type : type, ? containerRegistration.Type : type,
}; };
return registration.BuildChain.ExecuteThrowingPlan(ref context); return ExecutePlan(registration.BuildChain, ref context);
} }
#endregion #endregion
@ -197,7 +197,7 @@ namespace Unity
? containerRegistration.Type : type ? containerRegistration.Type : type
}; };
return registration.BuildChain.ExecuteThrowingPlan(ref context); return ExecutePlan(registration.BuildChain, ref context);
} }
#endregion #endregion

Просмотреть файл

@ -340,6 +340,34 @@ namespace Unity
return argType; return argType;
} }
private static object ExecutePlan(BuilderStrategy[] chain, ref BuilderContext context)
{
var i = -1;
try
{
while (!context.BuildComplete && ++i < chain.Length)
{
chain[i].PreBuildUp(ref context);
}
while (--i >= 0)
{
chain[i].PostBuildUp(ref context);
}
}
catch (Exception ex)
{
context.RequiresRecovery?.Recover();
// TODO: 5.9.0 Add proper error message
throw new ResolutionFailedException(context.RegistrationType,
context.RegistrationName,
"", ex);
}
return context.Existing;
}
#endregion #endregion

Просмотреть файл

@ -5,7 +5,6 @@ using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Unity.Builder; using Unity.Builder;
using Unity.Builder.Expressions;
using Unity.Exceptions; using Unity.Exceptions;
using Unity.Policy; using Unity.Policy;
using Unity.Registration; using Unity.Registration;
@ -164,8 +163,6 @@ namespace Unity
private ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context) private ResolveDelegate<BuilderContext> GetResolver(ref BuilderContext context)
{ {
context.Variable = Expression.Variable(context.Type, "instance");
var expressions = new List<Expression>(); var expressions = new List<Expression>();
foreach (var processor in _processorsChain) foreach (var processor in _processorsChain)
@ -174,11 +171,10 @@ namespace Unity
expressions.Add(step); expressions.Add(step);
} }
expressions.Add(Expression.Convert(context.Variable, typeof(object))); expressions.Add(BuilderContextExpression.Existing);
var lambda = Expression.Lambda<ResolveDelegate<BuilderContext>>( var lambda = Expression.Lambda<ResolveDelegate<BuilderContext>>(
Expression.Block(new ParameterExpression[] { context.Variable }, expressions), Expression.Block(expressions), BuilderContextExpression.Context);
BuilderContextExpression.Context);
return lambda.Compile(); return lambda.Compile();
} }
@ -194,7 +190,7 @@ namespace Unity
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendLine($"Resolution of the dependency failed for type = '{typeRequested}', name = '{FormatName(nameRequested)}'."); builder.AppendLine($"Resolution of the dependency failed for type = '{typeRequested}', name = '{FormatName(nameRequested)}'.");
builder.AppendLine($"Exception occurred while: {ExceptionReason(ref context)}."); builder.AppendLine($"Exception occurred while: {Constants.NoOperationExceptionReason}.");
builder.AppendLine($"Exception is: {innerException?.GetType().GetTypeInfo().Name ?? "ResolutionFailedException"} - {innerException?.Message}"); builder.AppendLine($"Exception is: {innerException?.GetType().GetTypeInfo().Name ?? "ResolutionFailedException"} - {innerException?.Message}");
builder.AppendLine("-----------------------------------------------"); builder.AppendLine("-----------------------------------------------");
builder.AppendLine("At the time of the exception, the container was: "); builder.AppendLine("At the time of the exception, the container was: ");
@ -227,33 +223,6 @@ namespace Unity
return string.IsNullOrEmpty(name) ? "(none)" : name; return string.IsNullOrEmpty(name) ? "(none)" : name;
} }
private static string ExceptionReason(ref BuilderContext context)
{
//var deepestContext = context;
//// Find deepest child
//while (deepestContext.ChildContext != null)
//{
// deepestContext = deepestContext.ChildContext;
//}
// Backtrack to last known operation
return Constants.NoOperationExceptionReason;
}
private static string OperationError(object operation)
{
switch (operation)
{
case ConstructorInfo ctor:
return $"Calling constructor {ctor}";
default:
return operation.ToString();
}
}
#endregion #endregion
} }

Просмотреть файл

@ -20,25 +20,28 @@ namespace Runner.Tests
_container.RegisterType<Poco>(); _container.RegisterType<Poco>();
_container.RegisterType<IService, Service>(); _container.RegisterType<IService, Service>();
_container.RegisterType<IService, Service>("1"); _container.RegisterType<IService, Service>("1");
_container.RegisterType<IService, Service>("2"); _container.RegisterType<IService>("2", Invoke.Factory(c => new Service()));
} }
[Benchmark(Description = "Resolve<IUnityContainer>")] [Benchmark(Description = "Resolve<IUnityContainer> ")]
public object IUnityContainer() => _container.Resolve(typeof(IUnityContainer), null); public object IUnityContainer() => _container.Resolve(typeof(IUnityContainer), null);
[Benchmark(Description = "Resolve<object> (unregistered)")] [Benchmark(Description = "Resolve<object> (unregistered)")]
public object Unregistered() => _container.Resolve(typeof(object), null); public object Unregistered() => _container.Resolve(typeof(object), null);
[Benchmark(Description = "Resolve<Poco> (registered)")] [Benchmark(Description = "Resolve<Poco> (registered)")]
public object Transient() => _container.Resolve(typeof(Poco), null); public object Transient() => _container.Resolve(typeof(Poco), null);
[Benchmark(Description = "Resolve<IService> (registered)")] [Benchmark(Description = "Resolve<IService> (registered)")]
public object Mapping() => _container.Resolve(typeof(IService), null); public object Mapping() => _container.Resolve(typeof(IService), null);
[Benchmark(Description = "Resolve<IService[]> (registered)")] [Benchmark(Description = "Resolve<IService> (factory)")]
public object Factory() => _container.Resolve(typeof(IService), "2");
[Benchmark(Description = "Resolve<IService[]> (registered)")]
public object Array() => _container.Resolve(typeof(IService[]), null); public object Array() => _container.Resolve(typeof(IService[]), null);
[Benchmark(Description = "Resolve<IEnumerable<IService>> (registered)")] [Benchmark(Description = "Resolve<IEnumerable<IService>> (registered)")]
public object Enumerable() => _container.Resolve(typeof(IEnumerable<IService>), null); public object Enumerable() => _container.Resolve(typeof(IEnumerable<IService>), null);

Просмотреть файл

@ -20,7 +20,7 @@ namespace Runner.Tests
_container.RegisterType<Poco>(); _container.RegisterType<Poco>();
_container.RegisterType<IService, Service>(); _container.RegisterType<IService, Service>();
_container.RegisterType<IService, Service>("1"); _container.RegisterType<IService, Service>("1");
_container.RegisterType<IService, Service>("2"); _container.RegisterType<IService>("2", Invoke.Factory(c => new Service()));
_container.Resolve<object>(); _container.Resolve<object>();
_container.Resolve<Poco>(); _container.Resolve<Poco>();
@ -41,6 +41,9 @@ namespace Runner.Tests
[Benchmark(Description = "Resolve<IService> (pre-built)")] [Benchmark(Description = "Resolve<IService> (pre-built)")]
public object Mapping() => _container.Resolve(typeof(IService), null); public object Mapping() => _container.Resolve(typeof(IService), null);
[Benchmark(Description = "Resolve<IService> (factory)")]
public object Factory() => _container.Resolve(typeof(IService), "2");
[Benchmark(Description = "Resolve<IService[]> (pre-built)")] [Benchmark(Description = "Resolve<IService[]> (pre-built)")]
public object Array() => _container.Resolve(typeof(IService[]), null); public object Array() => _container.Resolve(typeof(IService[]), null);

Просмотреть файл

@ -3,8 +3,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Unity.Injection; using Unity.Injection;
using Unity.Policy;
using Unity.ResolverPolicy;
using Unity.Tests.v5.Generics; using Unity.Tests.v5.Generics;
using Unity.Tests.v5.TestSupport; using Unity.Tests.v5.TestSupport;

Просмотреть файл

@ -5,7 +5,6 @@ using Unity.Builder;
using Unity.Extension; using Unity.Extension;
using Unity.Injection; using Unity.Injection;
using Unity.Policy; using Unity.Policy;
using Unity.ResolverPolicy;
using Unity.Strategies; using Unity.Strategies;
using Unity.Tests.v5.TestSupport; using Unity.Tests.v5.TestSupport;