This commit is contained in:
Eugene Sadovoi 2019-05-21 21:39:22 -04:00
Родитель bacb641231
Коммит c5069321ce
35 изменённых файлов: 513 добавлений и 143 удалений

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

@ -21,8 +21,6 @@ namespace Unity.Builder
{
#region Fields
private bool _async;
internal IPolicyList List { get; set; }
public delegate object? ResolvePlanDelegate(ref BuilderContext context, ResolveDelegate<BuilderContext> resolver);
@ -35,7 +33,7 @@ namespace Unity.Builder
public Type Type { get; set; }
public string? Name => Registration.Name;
public string? Name { get; set; }
public object? Resolve(Type type, string? name)
{
@ -74,7 +72,7 @@ namespace Unity.Builder
public object? Get(Type policyInterface)
{
return List?.Get(Type, Name, policyInterface) ??
Registration.Get(policyInterface);
Registration?.Get(policyInterface);
}
public object? Get(Type type, Type policyInterface)
@ -86,7 +84,7 @@ namespace Unity.Builder
{
return List?.Get(type, name, policyInterface) ?? (type != Type || name != Name
? ContainerContext.Get(type, name, policyInterface)
: Registration.Get(policyInterface));
: Registration?.Get(policyInterface));
}
public void Set(Type policyInterface, object policy)
@ -118,13 +116,12 @@ namespace Unity.Builder
public bool IsAsync { get; set; }
public bool Async { get => _async; set => _async = value; }
public ResolverOverride[] Overrides;
public object? Existing { get; set; }
public IRegistration Registration { get; set; }
public IRegistration? Registration { get; set; }
public ContainerContext ContainerContext { get; set; }
@ -138,7 +135,9 @@ namespace Unity.Builder
{
get
{
if (null != Registration.PipelineDelegate) return Registration.PipelineDelegate;
if (null != Registration?.PipelineDelegate) return Registration.PipelineDelegate;
Debug.Assert(null != Registration);
lock (Registration)
{

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

@ -24,12 +24,12 @@ namespace Unity.Factories
#region TypeResolverFactory
public static TypeFactoryDelegate Factory = (Type type, IRegistration policies) =>
public static TypeFactoryDelegate Factory = (Type type, IRegistration? policies) =>
{
var typeArgument = type.GetElementType();
var targetType = policies.Owner.GetTargetType(typeArgument);
var targetType = policies?.Owner.GetTargetType(typeArgument);
if (typeArgument != targetType)
if (null != targetType && typeArgument != targetType)
{
return ((BuiltInFactoryDelegate)BuiltInMethod
.MakeGenericMethod(typeArgument)

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

@ -24,7 +24,7 @@ namespace Unity.Factories
#region TypeResolverFactory
public static TypeFactoryDelegate Factory = (Type type, IRegistration policies) =>
public static TypeFactoryDelegate Factory = (Type type, IRegistration? policies) =>
{
#if NETSTANDARD1_0 || NETCOREAPP1_0 || NET40
var typeArgument = type.GetTypeInfo().GenericTypeArguments.First();

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

@ -18,7 +18,7 @@ namespace Unity.Factories
#region TypeResolverFactory
public static TypeFactoryDelegate Factory = (Type type, IRegistration policies) =>
public static TypeFactoryDelegate Factory = (Type type, IRegistration? policies) =>
{
var typeToBuild = type.GetTypeInfo().GenericTypeArguments[0];
var factoryMethod = ImplementationMethod.MakeGenericMethod(typeToBuild);

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

@ -25,7 +25,7 @@ namespace Unity.Factories
#region TypeResolverFactory
public static TypeFactoryDelegate Factory = (Type type, IRegistration policies) =>
public static TypeFactoryDelegate Factory = (Type type, IRegistration? policies) =>
{
var itemType = type.GetTypeInfo().GenericTypeArguments[0];
var lazyMethod = ImplementationMethod.MakeGenericMethod(itemType);

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

@ -28,7 +28,7 @@ namespace Unity.Factories
#region ResolveDelegateFactory
public static TypeFactoryDelegate Factory = (Type type, IRegistration policies) =>
public static TypeFactoryDelegate Factory = (Type type, IRegistration? policies) =>
{
#if NETSTANDARD1_0 || NETCOREAPP1_0 || NET40

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

@ -5,5 +5,5 @@ using Unity.Resolution;
namespace Unity
{
public delegate ResolveDelegate<BuilderContext> TypeFactoryDelegate(Type type, IRegistration policies);
public delegate ResolveDelegate<BuilderContext> TypeFactoryDelegate(Type type, IRegistration? policies);
}

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

@ -5,6 +5,6 @@ using Unity.Registration;
namespace Unity
{
public delegate IEnumerable<object> MemberSelector<TMember>(Type type, IRegistration set)
public delegate IEnumerable<object> MemberSelector<TMember>(Type type, IRegistration? set)
where TMember : MemberInfo;
}

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

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Unity.Builder;
using Unity.Lifetime;
@ -8,34 +9,44 @@ namespace Unity
{
public ref partial struct PipelineBuilder
{
private PipelineDelegate DefaultLifetime()
private BuildPipelineAsync DefaultLifetimeAsync()
{
var type = Type;
var name = Name;
var manager = Registration.LifetimeManager;
var manager = Registration?.LifetimeManager;
var registration = Registration;
var synchronized = manager as SynchronizedLifetimeManager;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
Debug.Assert(null != manager);
return (ref BuilderContext context) =>
return (ref PipelineContext context) =>
{
var lifetime = context.ContainerContext.Lifetime;
var unity = context.ContainerContext;
var overrides = context.Overrides;
// In Sync mode just execute pipeline
if (!context.Async)
if (!context.RunAsync)
{
var value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value)
return new ValueTask<object?>(value);
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
var c = new BuilderContext
{
List = new PolicyList(),
IsAsync = true,
Type = type,
ContainerContext = unity,
Registration = registration,
Overrides = overrides,
DeclaringType = type,
};
try
{
// Compose down the chain
value = pipeline(ref context);
value = pipeline(ref c);
manager.SetValue(value, lifetime);
return new ValueTask<object?>(value);
}
@ -54,11 +65,9 @@ namespace Unity
}
// Async mode
var unity = context.ContainerContext;
var overrides = context.Overrides;
// Create and return a task that creates an object
var task = Task.Factory.StartNew(() =>
var task = Task.Factory.StartNew<object?>(() =>
{
var value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value) return value;
@ -90,5 +99,50 @@ namespace Unity
return new ValueTask<object?>(task);
};
}
private PipelineDelegate DefaultLifetime()
{
var type = Type;
var name = Name;
var manager = Registration?.LifetimeManager;
var registration = Registration;
var synchronized = manager as SynchronizedLifetimeManager;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
Debug.Assert(null != manager);
return (ref BuilderContext context) =>
{
var lifetime = context.ContainerContext.Lifetime;
var value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value)
return new ValueTask<object?>(value);
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
try
{
// Compose down the chain
value = pipeline(ref context);
manager.SetValue(value, lifetime);
return new ValueTask<object?>(value);
}
catch (Exception ex)// when (null != synchronized)
{
#if NET40 || NET45 || NETSTANDARD1_0
var taskSource = new TaskCompletionSource<object?>();
taskSource.SetException(ex);
var ext = taskSource.Task;
#else
var ext = Task.FromException<object?>(ex);
#endif
synchronized?.Recover();
return new ValueTask<object?>(ext);
}
};
}
}
}

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

@ -7,53 +7,47 @@ namespace Unity
{
public ref partial struct PipelineBuilder
{
private PipelineDelegate PerResolveLifetime()
private BuildPipelineAsync PerResolveLifetimeAsync()
{
var type = Type;
var name = Name;
var registration = Registration;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
return (ref PipelineContext context) =>
{
object value;
var lifetime = context.ContainerContext.Lifetime;
var unity = context.ContainerContext;
var overrides = context.Overrides;
// In Sync mode just execute pipeline
if (!context.Async)
if (!context.RunAsync)
{
// Get it from context
var manager = (LifetimeManager?)context.Get(typeof(LifetimeManager));
// Return if holds value
if (null != manager)
var c = new BuilderContext
{
value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value)
{
return new ValueTask<object?>(value);
}
}
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
List = new PolicyList(),
IsAsync = true,
Type = type,
ContainerContext = unity,
Registration = registration,
Overrides = overrides,
DeclaringType = type,
};
// Compose down the chain
value = pipeline(ref context);
value = pipeline(ref c);
return new ValueTask<object?>(value);
}
// Async mode
var unity = context.ContainerContext;
var overrides = context.Overrides;
// Create and return a task that creates an object
var task = Task.Factory.StartNew(() =>
var task = Task.Factory.StartNew<object?>(() =>
{
var c = new BuilderContext
{
List = new PolicyList(),
List = new PolicyList(),
IsAsync = true,
Type = type,
ContainerContext = unity,
@ -69,5 +63,41 @@ namespace Unity
return new ValueTask<object?>(task);
};
}
private PipelineDelegate PerResolveLifetime()
{
var type = Type;
var name = Name;
var registration = Registration;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
{
object value;
var lifetime = context.ContainerContext.Lifetime;
// Get it from context
var manager = (LifetimeManager?)context.Get(typeof(LifetimeManager));
// Return if holds value
if (null != manager)
{
value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value)
{
return new ValueTask<object?>(value);
}
}
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
// Compose down the chain
value = pipeline(ref context);
return new ValueTask<object?>(value);
};
}
}
}

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

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Unity.Builder;
using Unity.Exceptions;
@ -9,18 +10,19 @@ namespace Unity
{
public ref partial struct PipelineBuilder
{
private PipelineDelegate PerThreadLifetime()
private BuildPipelineAsync PerThreadLifetimeAsync()
{
var type = Type;
var name = Name;
var registration = Registration;
var manager = Registration.LifetimeManager;
var manager = Registration?.LifetimeManager;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
return (ref PipelineContext context) =>
{
// Verify is not async
if (context.IsAsync)
if (context.RunAsync || context.RunningAsync)
{
var ex = new InvalidRegistrationException("Lifetime:PerThread is not designed to participate in async operations");
#if NET40 || NET45 || NETSTANDARD1_0
@ -33,6 +35,78 @@ namespace Unity
return new ValueTask<object?>(ext);
}
Debug.Assert(null != manager);
// Compose
try
{
var unity = context.ContainerContext;
var overrides = context.Overrides;
var lifetime = context.ContainerContext.Lifetime;
var value = manager.GetValue(lifetime);
if (LifetimeManager.NoValue != value)
return new ValueTask<object?>(value);
var c = new BuilderContext
{
List = new PolicyList(),
IsAsync = true,
Type = type,
Name = name,
ContainerContext = unity,
Registration = registration,
Overrides = overrides,
DeclaringType = type,
Parent = IntPtr.Zero,
};
// Compose down the chain
value = pipeline(ref c);
manager.SetValue(value, lifetime);
return new ValueTask<object?>(value);
}
catch (Exception ex)// when (null != synchronized)
{
#if NET40 || NET45 || NETSTANDARD1_0
var taskSource = new TaskCompletionSource<object?>();
taskSource.SetException(ex);
var ext = taskSource.Task;
#else
var ext = Task.FromException<object?>(ex);
#endif
return new ValueTask<object?>(ext);
}
};
}
private PipelineDelegate PerThreadLifetime()
{
var type = Type;
var name = Name;
var registration = Registration;
var manager = Registration?.LifetimeManager;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
{
// Verify is not async
if (context.IsAsync)
{
var ex = new InvalidRegistrationException("Lifetime:PerThread is not designed to participate in async operations");
#if NET40 || NET45 || NETSTANDARD1_0
var taskSource = new TaskCompletionSource<object?>();
taskSource.SetException(ex);
var ext = taskSource.Task;
#else
var ext = Task.FromException<object?>(ex);
#endif
return new ValueTask<object?>(ext);
}
Debug.Assert(null != manager);
// Compose
try
{

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

@ -7,38 +7,49 @@ namespace Unity
{
public ref partial struct PipelineBuilder
{
private PipelineDelegate TransientLifetime()
private BuildPipelineAsync TransientLifetimeAsync()
{
var type = Type;
var name = Name;
var registration = Registration;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
return (ref PipelineContext context) =>
{
//In Sync mode just execute pipeline
if (!context.Async)
{
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
var value = pipeline(ref context);
return new ValueTask<object?>(value);
}
// Async mode
var unity = context.ContainerContext;
var overrides = context.Overrides;
// Create and return a task that creates an object
var task = Task.Factory.StartNew(() =>
//In Sync mode just execute pipeline
if (!context.RunAsync)
{
var c = new BuilderContext
{
List = new PolicyList(),
IsAsync = true,
Type = type,
Name = name,
ContainerContext = unity,
Registration = registration,
Overrides = overrides,
DeclaringType = type,
Parent = IntPtr.Zero,
};
// Execute pipeline
var value = pipeline(ref c);
return new ValueTask<object?>(value);
}
// Create and return a task that creates an object
var task = Task.Factory.StartNew<object?>(() =>
{
var c = new BuilderContext
{
List = new PolicyList(),
IsAsync = true,
Type = type,
Name = name,
ContainerContext = unity,
Registration = registration,
Overrides = overrides,
@ -53,5 +64,23 @@ namespace Unity
return new ValueTask<object?>(task);
};
}
private PipelineDelegate TransientLifetime()
{
var type = Type;
var name = Name;
var registration = Registration;
var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error));
return (ref BuilderContext context) =>
{
// Set Policy storage if required
if (null == context.List)
context.List = new PolicyList();
var value = pipeline(ref context);
return new ValueTask<object?>(value);
};
}
}
}

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

@ -37,20 +37,22 @@ namespace Unity
Seed = Registration.Pipeline;
_enumerator = pipelines.GetEnumerator();
Debug.Assert(null != _enumerator);
}
public PipelineBuilder(ref PipelineContext context)
public PipelineBuilder(ref PipelineContext context, IRegistration? registration = null)
{
Seed = null;
Type = context.Type;
Name = context.Name;
Registration = null;
Registration = registration;
ContainerContext = context.ContainerContext;
_enumerator = context.ContainerContext
.TypePipelineCache
.AsEnumerable<Pipeline>()
.GetEnumerator();
_enumerator = registration?.Processors?.GetEnumerator() ??
context.ContainerContext
.TypePipelineCache
.AsEnumerable<Pipeline>()
.GetEnumerator();
}
public PipelineBuilder(ref BuilderContext context)
@ -60,8 +62,9 @@ namespace Unity
Registration = context.Registration;
ContainerContext = context.ContainerContext;
Seed = Registration.Pipeline;
_enumerator = (context.Registration.Processors ?? Enumerable.Empty<Pipeline>()).GetEnumerator();
Seed = Registration?.Pipeline;
_enumerator = (context.Registration?.Processors ??
Enumerable.Empty<Pipeline>()).GetEnumerator();
}
#endregion
@ -88,7 +91,7 @@ namespace Unity
{
ref var context = ref this;
return _enumerator?.MoveNext() ?? false
? _enumerator.Current.Build(ref context)
? _enumerator?.Current?.Build(ref context) ?? Seed
: Seed;
}
@ -98,7 +101,7 @@ namespace Unity
ref var context = ref this;
return _enumerator?.MoveNext() ?? false
? _enumerator.Current.Build(ref context)
? _enumerator?.Current.Build(ref context) ?? Seed
: Seed;
}
@ -116,6 +119,20 @@ namespace Unity
};
}
public BuildPipelineAsync BuildPipelineAsync()
{
var manager = Registration?.LifetimeManager;
return manager switch
{
null => TransientLifetimeAsync(),
TransientLifetimeManager _ => TransientLifetimeAsync(),
PerResolveLifetimeManager _ => PerResolveLifetimeAsync(),
PerThreadLifetimeManager _ => PerThreadLifetimeAsync(),
_ => DefaultLifetimeAsync()
};
}
#endregion
}

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

@ -75,12 +75,12 @@ namespace Unity
#region Selection
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
var members = new List<InjectionMember>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<ConstructorInfo, object[]>)
{

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

@ -38,8 +38,8 @@ namespace Unity
.Where(ctor => !ctor.IsFamily && !ctor.IsPrivate && !ctor.IsStatic);
}
public override MemberSelector<ConstructorInfo> GetOrDefault(IPolicySet registration) =>
registration.Get<MemberSelector<ConstructorInfo>>() ??
public override MemberSelector<ConstructorInfo> GetOrDefault(IPolicySet? registration) =>
registration?.Get<MemberSelector<ConstructorInfo>>() ??
Defaults.SelectConstructor;
#endregion

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

@ -77,7 +77,7 @@ namespace Unity
};
}
var lifetimeManager = (LifetimeManager?)builder.Registration.Get(typeof(LifetimeManager));
var lifetimeManager = (LifetimeManager?)builder.Registration?.Get(typeof(LifetimeManager));
return lifetimeManager is PerResolveLifetimeManager
? GetPerResolveDelegate(info, resolvers, pipeline)

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

@ -12,10 +12,10 @@ namespace Unity
public partial class ConstructorPipeline
{
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<ConstructorInfo, object[]>)
{

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

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Builder;
@ -28,7 +29,8 @@ namespace Unity
// Try to get resolver
Type? generic = null;
var resolver = builder.Registration.Get(typeof(ResolveDelegate<BuilderContext>)) ??
var resolver = builder.Registration?.Pipeline ??
builder.Registration?.Get(typeof(ResolveDelegate<BuilderContext>)) ??
builder.ContainerContext.Get(builder.Type, typeof(ResolveDelegate<BuilderContext>));
if (null == resolver)
@ -40,7 +42,7 @@ namespace Unity
#endif
{
generic = builder.Type.GetGenericTypeDefinition();
resolver = builder.ContainerContext.Get(generic, builder.Registration.Name, typeof(ResolveDelegate<BuilderContext>)) ??
resolver = builder.ContainerContext.Get(generic, builder.Name, typeof(ResolveDelegate<BuilderContext>)) ??
builder.ContainerContext.Get(generic, typeof(ResolveDelegate<BuilderContext>));
}
}
@ -49,9 +51,9 @@ namespace Unity
if (null != resolver) return builder.Pipeline((ResolveDelegate<BuilderContext>)resolver);
// Try finding factory
TypeFactoryDelegate? factory = builder.Registration.Get<TypeFactoryDelegate>();
TypeFactoryDelegate? factory = builder.Registration?.Get<TypeFactoryDelegate>();
if (builder.Registration is ExplicitRegistration registration)
if (builder.Registration is ExplicitRegistration @explicit)
{
#if NETCOREAPP1_0 || NETSTANDARD1_0
if (null != builder.Type && builder.Type.GetTypeInfo().IsGenericType)
@ -62,7 +64,7 @@ namespace Unity
factory = (TypeFactoryDelegate?)builder.ContainerContext.Get(builder.Type.GetGenericTypeDefinition(),
typeof(TypeFactoryDelegate));
}
else if (builder.Type.IsArray)
else if (null != builder.Type && builder.Type.IsArray)
{
if (builder.Type.GetArrayRank() == 1)
{
@ -76,21 +78,21 @@ namespace Unity
}
}
}
else
else if(builder.Registration is ExplicitRegistration @implicit)
{
#if NETCOREAPP1_0 || NETSTANDARD1_0
if (builder.Type.GetTypeInfo().IsGenericType)
if (null != builder.Type && builder.Type.GetTypeInfo().IsGenericType)
#else
if (builder.Type.IsGenericType)
if (null != builder.Type && builder.Type.IsGenericType)
#endif
{
factory = (TypeFactoryDelegate?)builder.ContainerContext.Get(builder.Type.GetGenericTypeDefinition(),
typeof(TypeFactoryDelegate));
}
else if (builder.Type.IsArray)
else if (builder.Type?.IsArray ?? false)
{
if (builder.Type.GetArrayRank() == 1)
return builder.Pipeline(ArrayResolver.Factory(builder.Type, builder.Registration));
if (builder.Type?.GetArrayRank() == 1)
return builder.Pipeline(ArrayResolver.Factory(builder.Type, @implicit));
else
{
var message = $"Invalid array {builder.Type}. Only arrays of rank 1 are supported";
@ -99,6 +101,8 @@ namespace Unity
}
}
Debug.Assert(null != builder.Type);
return null != factory
? builder.Pipeline(factory(builder.Type, builder.Registration))
: builder.Pipeline();

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

@ -24,12 +24,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<FieldInfo, object> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -32,8 +32,8 @@ namespace Unity
protected override Type MemberType(FieldInfo info) => info.FieldType;
public override MemberSelector<FieldInfo> GetOrDefault(IPolicySet registration) =>
registration.Get<MemberSelector<FieldInfo>>() ?? Defaults.SelectField;
public override MemberSelector<FieldInfo> GetOrDefault(IPolicySet? registration) =>
registration?.Get<MemberSelector<FieldInfo>>() ?? Defaults.SelectField;
#endregion

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

@ -12,24 +12,24 @@ namespace Unity
{
var requestedType = builder.Type;
if (builder.Registration is ExplicitRegistration registration)
if (builder.Registration is ExplicitRegistration @explicit)
{
// Explicit Registration
if (null == registration.Type) return builder.Pipeline();
if (null == @explicit.Type) return builder.Pipeline();
builder.Type = (null == registration.BuildType)
? registration.Type
: registration.BuildType(registration.Type);
builder.Type = (null == @explicit.BuildType)
? @explicit.Type
: @explicit.BuildType(@explicit.Type);
}
else
else if (builder.Registration is ImplicitRegistration @implicit)
{
// Implicit Registration
if (null != builder.Registration.BuildType)
builder.Type = builder.Registration.BuildType(builder.Type);
if (null != @implicit.BuildType)
builder.Type = @implicit.BuildType(builder.Type);
}
// If nothing to map or build required, just create it
if (builder.Registration.BuildRequired || requestedType == builder.Type)
if ((builder.Registration?.BuildRequired ?? false) || requestedType == builder.Type)
return builder.Pipeline();
var type = builder.Type;

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

@ -125,7 +125,7 @@ namespace Unity
/// <param name="type"></param>
/// <param name="registration"></param>
/// <returns></returns>
public IEnumerable<Expression> GetExpressions(Type type, IRegistration registration)
public IEnumerable<Expression> GetExpressions(Type type, IRegistration? registration)
{
var selector = GetOrDefault(registration);
var members = selector(type, registration);
@ -180,9 +180,9 @@ namespace Unity
#endif
}
public virtual MemberSelector<TMemberInfo> GetOrDefault(IPolicySet registration)
public virtual MemberSelector<TMemberInfo> GetOrDefault(IPolicySet? registration)
{
return (MemberSelector<TMemberInfo>)(registration.Get(typeof(MemberSelector<TMemberInfo>)) ??
return (MemberSelector<TMemberInfo>)(registration?.Get(typeof(MemberSelector<TMemberInfo>)) ??
Defaults.Get(typeof(MemberSelector<TMemberInfo>)) ??
throw new InvalidOperationException("Should never be null"));
}

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

@ -8,12 +8,12 @@ namespace Unity
{
public abstract partial class MemberPipeline<TMemberInfo, TData>
{
public virtual IEnumerable<object> Select(Type type, IRegistration registration)
public virtual IEnumerable<object> Select(Type type, IRegistration? registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<TMemberInfo, TData> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -26,12 +26,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<MethodInfo, object[]> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -31,8 +31,8 @@ namespace Unity
!member.IsStatic);
}
public override MemberSelector<MethodInfo> GetOrDefault(IPolicySet registration) =>
registration.Get<MemberSelector<MethodInfo>>() ?? Defaults.SelectMethod;
public override MemberSelector<MethodInfo> GetOrDefault(IPolicySet? registration) =>
registration?.Get<MemberSelector<MethodInfo>>() ?? Defaults.SelectMethod;
#endregion

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

@ -9,12 +9,12 @@ namespace Unity
public partial class MethodPipeline
{
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<MethodInfo, object[]> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -25,12 +25,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IRegistration registration)
public override IEnumerable<object> Select(Type type, IRegistration? registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration?.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<PropertyInfo, object> && memberSet.Add(injectionMember))
yield return injectionMember;
@ -57,15 +57,15 @@ namespace Unity
yield return new InvalidRegistrationException(
$"Indexer '{member.Name}' on type '{type?.Name}' is marked for injection. Indexers cannot be injected");
if (setter.IsStatic)
if (setter?.IsStatic ?? false)
yield return new InvalidRegistrationException(
$"Static property '{member.Name}' on type '{type?.Name}' is marked for injection. Static properties cannot be injected");
if (setter.IsPrivate)
if (setter?.IsPrivate ?? false)
yield return new InvalidRegistrationException(
$"Private property '{member.Name}' on type '{type?.Name}' is marked for injection. Private properties cannot be injected");
if (setter.IsFamily)
if (setter?.IsFamily ?? false)
yield return new InvalidRegistrationException(
$"Protected property '{member.Name}' on type '{type?.Name}' is marked for injection. Protected properties cannot be injected");

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

@ -39,8 +39,8 @@ namespace Unity
}
}
public override MemberSelector<PropertyInfo> GetOrDefault(IPolicySet registration) =>
registration.Get<MemberSelector<PropertyInfo>>() ?? Defaults.SelectProperty;
public override MemberSelector<PropertyInfo> GetOrDefault(IPolicySet? registration) =>
registration?.Get<MemberSelector<PropertyInfo>>() ?? Defaults.SelectProperty;
#endregion

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

@ -104,6 +104,27 @@ namespace Unity.Storage
#region Public Members
internal void Set(Type type, string? name, BuildPipelineAsync pipeline)
{
var key = new HashKey(type, name);
var targetBucket = key.HashCode % Buckets.Length;
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
{
ref var candidate = ref Entries[i];
if (candidate.Key != key) continue;
candidate.Pipeline = pipeline;
return;
}
ref var entry = ref Entries[Count];
entry.Key = key;
entry.Next = Buckets[targetBucket];
entry.Pipeline = pipeline;
Buckets[targetBucket] = Count++;
}
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
(float)Count / Entries.Length > 0.72f;
#endregion

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

@ -150,7 +150,6 @@ namespace Unity.Storage
Buckets[targetBucket] = Count++;
}
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
(float)Count / Entries.Length > 0.72f;
#endregion

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

@ -132,6 +132,9 @@ namespace Unity
container.LifetimeContainer.Remove(disposable);
disposable.Dispose();
}
// Check what strategies to run
registration.Processors = Context.InstancePipelineCache;
// Raise event
container.RegisteringInstance?.Invoke(this, new RegisterInstanceEventArgs(registeredType, instance, name, manager));

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

@ -133,9 +133,9 @@ namespace Unity
#if NETSTANDARD1_0 || NETCOREAPP1_0
var infoFrom = typeFrom?.GetTypeInfo();
var infoTo = typeTo?.GetTypeInfo();
if (!infoFrom.IsGenericType && !infoTo.IsGenericType && !infoFrom.IsAssignableFrom(infoTo))
if (null != infoTo && null != infoFrom && !infoFrom.IsGenericType && !infoTo.IsGenericType && !infoFrom.IsAssignableFrom(infoTo))
#else
if (!typeFrom.IsGenericType && !typeTo.IsGenericType && !typeFrom.IsAssignableFrom(typeTo))
if (null != typeTo && null != typeFrom && !typeFrom.IsGenericType && !typeTo.IsGenericType && !typeFrom.IsAssignableFrom(typeTo))
#endif
throw new ArgumentException($"The type {typeTo} cannot be assigned to variables of type {typeFrom}.");

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

@ -1,14 +1,24 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Security;
using System.Threading.Tasks;
using Unity.Builder;
using Unity.Registration;
using Unity.Storage;
namespace Unity
{
public partial class UnityContainer
{
#region Container Resolution
[SecuritySafeCritical]
private static ValueTask<object?> ResolveContainerPipeline(ref PipelineContext context)
=> new ValueTask<object?>(context.ContainerContext.Container);
#endregion
private BuildPipelineAsync? GetPipeline(Type type, string? name)
{
var key = new HashKey(type, name);
@ -39,11 +49,141 @@ namespace Unity
#region Root Build Pipeline
[SecuritySafeCritical]
public ValueTask<object?> DefaultBuildPipeline(ref PipelineContext context)
public ValueTask<object?> BuildPipeline(ref PipelineContext context)
{
var builder = new PipelineBuilder(ref PipelineContext context);
// Get Registration if exists
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = context.Type.GetTypeInfo();
var registration = info.IsGenericType
? GetGenericExplicitRegistration(context.Type, context.Name, info)
: GetSimpleExplicitRegistration(context.Type, context.Name);
#else
var registration = context.Type.IsGenericType
? GetGenericExplicitRegistration(context.Type, context.Name)
: GetSimpleExplicitRegistration(context.Type, context.Name);
#endif
// Build Pipeline
var builder = new PipelineBuilder(ref context, registration);
var pipeline = builder.BuildPipelineAsync();
throw new NotImplementedException();
return pipeline(ref context);
}
#endregion
#region Get Registration
private IRegistration? GetSimpleExplicitRegistration(Type type, string? name)
{
var key = new HashKey(type, name);
// Iterate through containers hierarchy
for (UnityContainer? container = this; null != container; container = container._parent)
{
// Skip to parent if no registrations
if (null == container._metadata) continue;
Debug.Assert(null != container._registry);
var registry = container._registry;
// Check for exact match
for (var i = registry.Buckets[key.HashCode % registry.Buckets.Length]; i >= 0; i = registry.Entries[i].Next)
{
ref var candidate = ref registry.Entries[i];
if (candidate.Key != key) continue;
// Found a registration
if (!(candidate.Policies is IRegistration))
candidate.Policies = container.CreateRegistration(type, name, candidate.Policies);
return (IRegistration)candidate.Policies;
}
}
Debug.Assert(null != _root);
return null;
}
#if NETSTANDARD1_0 || NETCOREAPP1_0
private IRegistration? GetGenericExplicitRegistration(Type type, string? name, TypeInfo info)
#else
private IRegistration? GetGenericExplicitRegistration(Type type, string? name)
#endif
{
bool initGenerics = true;
Type? generic = null;
int targetBucket;
var keyExact = new HashKey(type, name);
var keyGeneric = new HashKey();
var keyDefault = new HashKey();
// Iterate through containers hierarchy
for (UnityContainer? container = this; null != container; container = container._parent)
{
// Skip to parent if no registrations
if (null == container._metadata) continue;
Debug.Assert(null != container._registry);
var registry = container._registry;
// Check for exact match
targetBucket = keyExact.HashCode % registry.Buckets.Length;
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var candidate = ref registry.Entries[i];
if (candidate.Key != keyExact) continue;
// Found a registration
if (!(candidate.Policies is IRegistration))
candidate.Policies = container.CreateRegistration(type, name, candidate.Policies);
return (IRegistration)candidate.Policies;
}
// Generic registrations
if (initGenerics)
{
initGenerics = false;
#if NETSTANDARD1_0 || NETCOREAPP1_0
generic = info.GetGenericTypeDefinition();
#else
generic = type.GetGenericTypeDefinition();
#endif
keyGeneric = new HashKey(generic, name);
keyDefault = new HashKey(generic);
}
// Check for factory with same name
targetBucket = keyGeneric.HashCode % registry.Buckets.Length;
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var candidate = ref registry.Entries[i];
if (candidate.Key != keyGeneric)
continue;
// Found a factory
return container.GetOrAdd(ref keyExact, type, name, candidate.Policies);
}
// Check for default factory
targetBucket = keyDefault.HashCode % registry.Buckets.Length;
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var candidate = ref registry.Entries[i];
if (candidate.Key != keyDefault)
continue;
// Found a factory
return container.GetOrAdd(ref keyExact, type, name, candidate.Policies);
}
}
return null;
}
#endregion

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

@ -62,16 +62,18 @@ namespace Unity
// IUnityContainer, IUnityContainerAsync
var container = new ExplicitRegistration(this, null, typeof(UnityContainer))
{
Pipeline = (ref BuilderContext c) => c.Async ? (object)Task.FromResult<object>(c.Container) : c.Container,
Pipeline = (ref BuilderContext c) => c.Container,
PipelineDelegate = (ref BuilderContext c) => new ValueTask<object?>(c.Container)
};
// Create Registry
// Create Registries
_metadata = new Metadata();
_registry = new Registry(Defaults);
_pipelines = new Pipelines(DefaultBuildPipeline);
_registry.Set(typeof(IUnityContainer), null, container);
_registry.Set(typeof(IUnityContainerAsync), null, container);
_pipelines = new Pipelines(BuildPipeline);
_pipelines.Set(typeof(IUnityContainer), null, ResolveContainerPipeline);
_pipelines.Set(typeof(IUnityContainerAsync), null, ResolveContainerPipeline);
/////////////////////////////////////////////////////////////
// Built-In Features
@ -114,6 +116,7 @@ namespace Unity
},
new StagedStrategyChain<Pipeline, Stage> // Instance Resolve Pipeline
{
{ factory, Stage.Factory }
});
}
else
@ -143,6 +146,7 @@ namespace Unity
new StagedStrategyChain<Pipeline, Stage> // Instance Resolve Pipeline
{
{ diagnostic, Stage.Diagnostic },
{ factory, Stage.Factory }
});
// Build process

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

@ -63,11 +63,7 @@ namespace Unity
public static TConfigurator Configure<TConfigurator>(this IUnityContainer container)
where TConfigurator : IUnityContainerExtensionConfigurator
{
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
return (TConfigurator)(container ?? throw new ArgumentNullException(nameof(container))).Configure(typeof(TConfigurator));
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning restore CS8603 // Possible null reference return.
}
#endregion