diff --git a/package.props b/package.props
index 66e6c4c6..d99d3d47 100644
--- a/package.props
+++ b/package.props
@@ -2,7 +2,7 @@
6.0.0
- netstandard2.0;netstandard1.0;netcoreapp2.0;netcoreapp1.0;net47;net46;net45;net40
+ netstandard2.0;netstandard1.0;netcoreapp2.0;netcoreapp1.0;net47;net46;net45
diff --git a/src/Abstracts/BuilderStrategy.cs b/src/Abstracts/BuilderStrategy.cs
index c46be3f8..06e217a4 100644
--- a/src/Abstracts/BuilderStrategy.cs
+++ b/src/Abstracts/BuilderStrategy.cs
@@ -1,8 +1,8 @@
using System;
-using System.Reflection;
using Unity.Builder;
using Unity.Injection;
using Unity.Registration;
+using Unity.Resolution;
namespace Unity.Strategies
{
@@ -12,6 +12,13 @@ namespace Unity.Strategies
///
public abstract class BuilderStrategy
{
+ #region Composition
+
+ public virtual ResolveDelegate? BuildResolver(UnityContainer container, Type type, ImplicitRegistration registration, ResolveDelegate? seed) => seed;
+
+ #endregion
+
+
#region Build
///
@@ -48,7 +55,7 @@ namespace Unity.Strategies
/// Reference to registration
///
/// Returns true if this strategy will participate in building of registered type
- public virtual bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[] injectionMembers)
+ public virtual bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[]? injectionMembers)
{
return true;
}
diff --git a/src/Abstracts/IRegexEnumerable.cs b/src/Abstracts/IRegexEnumerable.cs
new file mode 100644
index 00000000..07e5bc37
--- /dev/null
+++ b/src/Abstracts/IRegexEnumerable.cs
@@ -0,0 +1,6 @@
+namespace Unity.Abstracts
+{
+ public interface IRegex
+ {
+ }
+}
diff --git a/src/Builder/Context/BuilderContext.cs b/src/Builder/Context/BuilderContext.cs
index 44dd2c4c..3748f20c 100644
--- a/src/Builder/Context/BuilderContext.cs
+++ b/src/Builder/Context/BuilderContext.cs
@@ -22,10 +22,10 @@ namespace Unity.Builder
{
#region Fields
- public ResolverOverride[] Overrides;
+ public ResolverOverride[]? Overrides;
internal IPolicyList List;
- public delegate object ExecutePlanDelegate(BuilderStrategy[] chain, ref BuilderContext context);
+ public delegate object ExecutePlanDelegate(BuilderStrategy[]? chain, ref BuilderContext context);
public delegate object ResolvePlanDelegate(ref BuilderContext context, ResolveDelegate resolver);
#endregion
@@ -35,11 +35,42 @@ namespace Unity.Builder
public IUnityContainer Container => Lifetime?.Container;
- public Type Type { get; set; }
+ public Type? Type { get; set; }
- public string Name { get; set; }
+ public string? Name { get; set; }
- public object Resolve(Type type, string name)
+ public object? Resolve()
+ {
+ if (null == Type) return null;
+
+ // Process overrides if any
+ if (null != Overrides)
+ {
+ NamedType namedType = new NamedType
+ {
+ Type = Type,
+ Name = Name
+ };
+
+ // 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 IResolve resolverPolicy &&
+ resolverOverride is IEquatable comparer && comparer.Equals(namedType))
+ {
+ var context = this;
+
+ return ResolvePlan(ref context, resolverPolicy.Resolve);
+ }
+ }
+ }
+
+ return Resolve(Type, Name, ((UnityContainer)Container).GetRegistration(Type, Name));
+ }
+
+ public object Resolve(Type type, string? name)
{
// Process overrides if any
if (null != Overrides)
@@ -79,12 +110,12 @@ namespace Unity.Builder
Registration.Get(policyInterface);
}
- public object Get(Type type, Type policyInterface)
+ public object? Get(Type type, Type policyInterface)
{
return ((UnityContainer)Container).GetPolicy(type, policyInterface);
}
- public object Get(Type type, string name, Type policyInterface)
+ public object? Get(Type type, string? name, Type policyInterface)
{
return List.Get(type, name, policyInterface) ??
(type != RegistrationType || name != Name
@@ -102,12 +133,12 @@ namespace Unity.Builder
List.Set(type, policyInterface, policy);
}
- public void Set(Type type, string name, Type policyInterface, object policy)
+ 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)
+ public void Clear(Type type, string? name, Type policyInterface)
{
List.Clear(type, name, policyInterface);
}
@@ -126,7 +157,7 @@ namespace Unity.Builder
#region Public Properties
- public object Existing { get; set; }
+ public object? Existing { get; set; }
public ILifetimeContainer Lifetime;
@@ -134,7 +165,7 @@ namespace Unity.Builder
public bool BuildComplete;
- public Type DeclaringType;
+ public Type? DeclaringType;
#if !NET40
public IntPtr Parent;
#endif
@@ -147,7 +178,7 @@ namespace Unity.Builder
#region Resolve Methods
- public object Resolve(Type type, string name, ImplicitRegistration registration)
+ public object Resolve(Type type, string? name, ImplicitRegistration registration)
{
unsafe
{
@@ -218,7 +249,7 @@ namespace Unity.Builder
return value;
}
- public object Resolve(PropertyInfo property, object value)
+ public object? Resolve(PropertyInfo property, object value)
{
var context = this;
@@ -273,7 +304,7 @@ namespace Unity.Builder
return value;
}
- public object Resolve(FieldInfo field, object value)
+ public object? Resolve(FieldInfo field, object value)
{
var context = this;
@@ -339,9 +370,9 @@ namespace Unity.Builder
if (Registration is ExplicitRegistration registration)
{
#if NETCOREAPP1_0 || NETSTANDARD1_0
- if (Type?.GetTypeInfo().IsGenericType ?? false)
+ if (null != Type && Type.GetTypeInfo().IsGenericType)
#else
- if (Type?.IsGenericType ?? false)
+ if (null != Type && Type.IsGenericType)
#endif
return Registration.Get>() ??
((UnityContainer)Container).GetResolverPolicy(Type.GetGenericTypeDefinition(), Name);
@@ -359,9 +390,9 @@ namespace Unity.Builder
if (Registration is ExplicitRegistration registration)
{
#if NETCOREAPP1_0 || NETSTANDARD1_0
- if (Type?.GetTypeInfo().IsGenericType ?? false)
+ if (null != Type && Type.GetTypeInfo().IsGenericType)
#else
- if (Type?.IsGenericType ?? false)
+ if (null != Type && Type.IsGenericType)
#endif
{
return ((UnityContainer)Container).GetFactoryPolicy(Type.GetGenericTypeDefinition(), Name) ??
diff --git a/src/Composition/CompositionContext.cs b/src/Composition/CompositionContext.cs
new file mode 100644
index 00000000..58462f34
--- /dev/null
+++ b/src/Composition/CompositionContext.cs
@@ -0,0 +1,15 @@
+using System;
+using Unity.Registration;
+using Unity.Resolution;
+
+namespace Unity.Composition
+{
+ public ref struct CompositionContext
+ {
+ public Type Type;
+ public string? Name;
+ public ResolverOverride[]? Overrides;
+ public ImplicitRegistration Registration;
+ public UnityContainer Container;
+ }
+}
diff --git a/src/Composition/CompositionDelegate.cs b/src/Composition/CompositionDelegate.cs
new file mode 100644
index 00000000..cdf87fcd
--- /dev/null
+++ b/src/Composition/CompositionDelegate.cs
@@ -0,0 +1,6 @@
+using Unity.Resolution;
+
+namespace Unity.Composition
+{
+ public delegate object? CompositionDelegate(UnityContainer container, object? existing, ResolverOverride[] overrides);
+}
diff --git a/src/Events/NamedEventArgs.cs b/src/Events/NamedEventArgs.cs
index f4537ca8..a766bbeb 100644
--- a/src/Events/NamedEventArgs.cs
+++ b/src/Events/NamedEventArgs.cs
@@ -9,7 +9,7 @@ namespace Unity.Events
///
public abstract class NamedEventArgs : EventArgs
{
- private string _name;
+ private string? _name;
///
/// Create a new with a null name.
@@ -22,7 +22,7 @@ namespace Unity.Events
/// Create a new with the given name.
///
/// Name to store.
- protected NamedEventArgs(string name)
+ protected NamedEventArgs(string? name)
{
_name = name;
}
@@ -31,7 +31,7 @@ namespace Unity.Events
/// The name.
///
/// Name used for this EventArg object.
- public virtual string Name
+ public virtual string? Name
{
get => _name;
set => _name = value;
diff --git a/src/Events/RegisterInstanceEventArgs.cs b/src/Events/RegisterInstanceEventArgs.cs
index 526517bf..56b1f52b 100644
--- a/src/Events/RegisterInstanceEventArgs.cs
+++ b/src/Events/RegisterInstanceEventArgs.cs
@@ -24,7 +24,7 @@ namespace Unity.Events
/// Name to register under, null if default registration.
/// object that handles how
/// the instance will be owned.
- public RegisterInstanceEventArgs(Type registeredType, object instance, string name, LifetimeManager lifetimeManager)
+ public RegisterInstanceEventArgs(Type? registeredType, object? instance, string? name, LifetimeManager? lifetimeManager)
: base(name)
{
RegisteredType = registeredType;
@@ -38,18 +38,18 @@ namespace Unity.Events
///
/// Type of instance being registered.
///
- public Type RegisteredType { get; }
+ public Type? RegisteredType { get; }
///
/// Instance object being registered.
///
/// Instance object being registered
- public object Instance { get; }
+ public object? Instance { get; }
///
/// that controls ownership of
/// this instance.
///
- public LifetimeManager LifetimeManager { get; }
+ public LifetimeManager? LifetimeManager { get; }
}
}
diff --git a/src/Extension/UnityContainerExtension.cs b/src/Extension/UnityContainerExtension.cs
index d8b9973d..6b9bc48f 100644
--- a/src/Extension/UnityContainerExtension.cs
+++ b/src/Extension/UnityContainerExtension.cs
@@ -1,17 +1,15 @@
-
-
-using System;
+using System;
namespace Unity.Extension
{
+ #pragma warning disable CS8618
+
+ // Non-nullable field is uninitialized.
///
/// Base class for all extension objects.
///
public abstract class UnityContainerExtension : IUnityContainerExtensionConfigurator
{
- private IUnityContainer _container;
- private ExtensionContext _context;
-
///
/// The container calls this method when the extension is added.
///
@@ -24,8 +22,9 @@ namespace Unity.Extension
throw new ArgumentNullException(nameof(context));
}
- _container = context.Container;
- _context = context;
+ Container = context.Container;
+ Context = context;
+
Initialize();
}
@@ -33,13 +32,13 @@ namespace Unity.Extension
/// The container this extension has been added to.
///
/// The that this extension has been added to.
- public IUnityContainer Container => _container;
+ public IUnityContainer Container { get; private set; }
///
/// The object used to manipulate
/// the inner state of the container.
///
- protected ExtensionContext Context => _context;
+ protected ExtensionContext Context { get; private set; }
///
/// Initial the container with this extension's functionality.
@@ -49,22 +48,7 @@ namespace Unity.Extension
/// by adding strategies, policies, etc. to
/// install it's functions into the container.
protected abstract void Initialize();
-
- ///
- /// Removes the extension's functions from the container.
- ///
- ///
- ///
- /// This method is called when extensions are being removed from the container. It can be
- /// used to do things like disconnect event handlers or clean up member state. You do not
- /// need to remove strategies or policies here; the container will do that automatically.
- ///
- ///
- /// The default implementation of this method does nothing.
- ///
- public virtual void Remove()
- {
- // Do nothing by default, can be overridden to do whatever you want.
- }
}
+
+ #pragma warning restore CS8618 // Non-nullable field is uninitialized.
}
diff --git a/src/Extensions/MetadataExtensions.cs b/src/Extensions/MetadataExtensions.cs
index 111e54e9..4d67c923 100644
--- a/src/Extensions/MetadataExtensions.cs
+++ b/src/Extensions/MetadataExtensions.cs
@@ -5,7 +5,7 @@ namespace Unity.Extensions
{
internal static class MetadataExtensions
{
- internal static int GetEntries(this Registry metadata, int hashCode, out int[] data)
+ internal static int GetEntries(this Registry metadata, int hashCode, out int[]? data)
{
var targetBucket = (hashCode & UnityContainer.HashMask) % metadata.Buckets.Length;
@@ -28,7 +28,7 @@ namespace Unity.Extensions
return 0;
}
- internal static int GetEntries(this Registry metadata, int hashCode, Type type, out int[] data)
+ internal static int GetEntries(this Registry metadata, int hashCode, Type type, out int[]? data)
{
var targetBucket = (hashCode & UnityContainer.HashMask) % metadata.Buckets.Length;
diff --git a/src/Extensions/RegistryExtensions.cs b/src/Extensions/RegistryExtensions.cs
index a858be19..be2bdf9e 100644
--- a/src/Extensions/RegistryExtensions.cs
+++ b/src/Extensions/RegistryExtensions.cs
@@ -1,6 +1,5 @@
using System;
using Unity.Policy;
-using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
@@ -10,7 +9,7 @@ namespace Unity.Extensions
{
#region Get
- public static IPolicySet Get(this Registry registry, int hashCode, Type type)
+ public static IPolicySet? Get(this Registry registry, int hashCode, Type? type)
{
var targetBucket = (hashCode & UnityContainer.HashMask) % registry.Buckets.Length;
@@ -29,7 +28,7 @@ namespace Unity.Extensions
#region Set
- internal static void Set(this Registry registry, Type type, ImplicitRegistration registration)
+ internal static void Set(this Registry registry, Type type, IPolicySet set)
{
var hashCode = type.GetHashCode();
var targetBucket = (hashCode & UnityContainer.HashMask) % registry.Buckets.Length;
@@ -38,7 +37,7 @@ namespace Unity.Extensions
{
ref var candidate = ref registry.Entries[i];
if (candidate.HashCode != hashCode || candidate.Key.Type != type) continue;
- candidate.Value = registration;
+ candidate.Value = set;
return;
}
@@ -46,11 +45,11 @@ namespace Unity.Extensions
entry.HashCode = hashCode;
entry.Next = registry.Buckets[targetBucket];
entry.Key.Type = type;
- entry.Value = registration;
+ entry.Value = set;
registry.Buckets[targetBucket] = registry.Count++;
}
- internal static void Set(this Registry registry, Type type, string name, ImplicitRegistration registration)
+ internal static void Set(this Registry registry, Type type, string? name, IPolicySet set)
{
var hashCode = NamedType.GetHashCode(type, name);
var targetBucket = (hashCode & UnityContainer.HashMask) % registry.Buckets.Length;
@@ -59,7 +58,7 @@ namespace Unity.Extensions
{
ref var candidate = ref registry.Entries[i];
if (candidate.HashCode != hashCode || candidate.Key.Type != type || candidate.Key.Name != name) continue;
- candidate.Value = registration;
+ candidate.Value = set;
return;
}
@@ -68,7 +67,7 @@ namespace Unity.Extensions
entry.Next = registry.Buckets[targetBucket];
entry.Key.Type = type;
entry.Key.Name = name;
- entry.Value = registration;
+ entry.Value = set;
registry.Buckets[targetBucket] = registry.Count++;
}
diff --git a/src/Factories/RegExResolver.cs b/src/Factories/RegExResolver.cs
new file mode 100644
index 00000000..86003900
--- /dev/null
+++ b/src/Factories/RegExResolver.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using Unity.Builder;
+using Unity.Policy;
+using Unity.Resolution;
+
+namespace Unity.Factories
+{
+ public class RegExResolver
+ {
+ #region Fields
+
+ private static readonly MethodInfo EnumerableMethod =
+ typeof(RegExResolver).GetTypeInfo()
+ .GetDeclaredMethod(nameof(RegExResolver.Resolver));
+
+ private static readonly MethodInfo EnumerableFactory =
+ typeof(RegExResolver).GetTypeInfo()
+ .GetDeclaredMethod(nameof(RegExResolver.ResolverFactory));
+
+ #endregion
+
+
+ #region ResolveDelegateFactory
+
+ public static ResolveDelegateFactory Factory = (ref BuilderContext context) =>
+ {
+
+#if NETSTANDARD1_0 || NETCOREAPP1_0 || NET40
+ var typeArgument = context.Type.GetTypeInfo().GenericTypeArguments.First();
+ if (typeArgument.GetTypeInfo().IsGenericType)
+#else
+ var typeArgument = context.Type.GenericTypeArguments.First();
+ if (typeArgument.IsGenericType)
+#endif
+ {
+ return ((EnumerableFactoryDelegate)
+ EnumerableFactory.MakeGenericMethod(typeArgument)
+ .CreateDelegate(typeof(EnumerableFactoryDelegate)))();
+ }
+ else
+ {
+ return (ResolveDelegate)
+ EnumerableMethod.MakeGenericMethod(typeArgument)
+ .CreateDelegate(typeof(ResolveDelegate));
+ }
+ };
+
+ #endregion
+
+
+ #region Implementation
+
+ private static object Resolver(ref BuilderContext context)
+ {
+ return ((UnityContainer)context.Container).ResolveEnumerable(context.Resolve,
+ context.Name);
+ }
+
+ private static ResolveDelegate ResolverFactory()
+ {
+ Type type = typeof(TElement).GetGenericTypeDefinition();
+ return (ref BuilderContext c) => ((UnityContainer)c.Container).ResolveEnumerable(c.Resolve, type, c.Name);
+ }
+
+ #endregion
+
+
+ #region Nested Types
+
+ private delegate ResolveDelegate EnumerableFactoryDelegate();
+
+ #endregion
+ }
+}
diff --git a/src/Lifetime/ContainerLifetimeManager.cs b/src/Lifetime/ContainerLifetimeManager.cs
deleted file mode 100644
index f7867676..00000000
--- a/src/Lifetime/ContainerLifetimeManager.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace Unity.Lifetime
-{
- ///
- /// Internal container lifetime manager.
- /// This manager distinguishes internal registration from user mode registration.
- ///
- ///
- /// Works like the ExternallyControlledLifetimeManager, but uses
- /// regular instead of weak references
- ///
- internal class ContainerLifetimeManager : LifetimeManager, IInstanceLifetimeManager
- {
- public override object GetValue(ILifetimeContainer container = null)
- {
- return container.Container;
- }
-
- protected override LifetimeManager OnCreateLifetimeManager()
- {
- return new ContainerLifetimeManager();
- }
- }
-}
diff --git a/src/Policy/DefaultPolicies.cs b/src/Policy/DefaultPolicies.cs
index f5132ce9..ee868ebf 100644
--- a/src/Policy/DefaultPolicies.cs
+++ b/src/Policy/DefaultPolicies.cs
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
+using Unity.Composition;
using Unity.Storage;
namespace Unity.Policy
@@ -18,6 +19,8 @@ namespace Unity.Policy
#region Public Members
+ public CompositionDelegate ComposeMethod { get; set; }
+
public ISelect CtorSelector { get; set; }
public ISelect PropertiesSelector { get; set; }
@@ -39,43 +42,45 @@ namespace Unity.Policy
public override object Get(Type policyInterface)
{
- switch (policyInterface)
+ return policyInterface switch
{
- case Type type when (typeof(ISelect) == type):
- return CtorSelector;
+ Type type when typeof(ISelect) == type => CtorSelector,
+ Type type when typeof(ISelect) == type => PropertiesSelector,
+ Type type when typeof(ISelect) == type => MethodsSelector,
+ Type type when typeof(ISelect) == type => FieldsSelector,
+ Type type when typeof(ResolveDelegateFactory) == type => ResolveDelegateFactory,
+ Type type when typeof(CompositionDelegate) == type => ComposeMethod,
- case Type type when (typeof(ISelect) == type):
- return PropertiesSelector;
-
- case Type type when (typeof(ISelect) == type):
- return MethodsSelector;
-
- case Type type when (typeof(ISelect) == type):
- return FieldsSelector;
-
- default:
- return base.Get(policyInterface);
- }
+ _ => base.Get(policyInterface)
+ };
}
public override void Set(Type policyInterface, object policy)
{
switch (policyInterface)
{
- case ISelect constructor:
- CtorSelector = constructor;
+ case Type type when typeof(ISelect) == type:
+ CtorSelector = (ISelect)policy;
break;
- case ISelect property:
- PropertiesSelector = property;
+ case Type type when typeof(ISelect) == type:
+ PropertiesSelector = (ISelect)policy;
break;
- case ISelect method:
- MethodsSelector = method;
+ case Type type when typeof(ISelect) == type:
+ MethodsSelector = (ISelect)policy;
break;
- case ISelect field:
- FieldsSelector = field;
+ case Type type when typeof(ISelect) == type:
+ FieldsSelector = (ISelect)policy;
+ break;
+
+ case Type type when typeof(ResolveDelegateFactory) == type:
+ ResolveDelegateFactory = (ResolveDelegateFactory)policy;
+ break;
+
+ case Type type when typeof(CompositionDelegate) == type:
+ ComposeMethod = (CompositionDelegate)policy;
break;
default:
diff --git a/src/Policy/IResolveDelegateFactory.cs b/src/Policy/ResolveDelegateFactory.cs
similarity index 100%
rename from src/Policy/IResolveDelegateFactory.cs
rename to src/Policy/ResolveDelegateFactory.cs
diff --git a/src/Registration/ExplicitRegistration.cs b/src/Registration/ExplicitRegistration.cs
index 878d320f..5be7e033 100644
--- a/src/Registration/ExplicitRegistration.cs
+++ b/src/Registration/ExplicitRegistration.cs
@@ -13,7 +13,7 @@ namespace Unity.Registration
{
#region Constructors
- public ExplicitRegistration(Type mappedTo, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
+ public ExplicitRegistration(Type? mappedTo, LifetimeManager lifetimeManager, InjectionMember[]? injectionMembers = null)
{
Type = mappedTo;
Key = typeof(LifetimeManager);
@@ -24,24 +24,24 @@ namespace Unity.Registration
}
- public ExplicitRegistration(IPolicySet validators, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
+ public ExplicitRegistration(IPolicySet? validators, LifetimeManager lifetimeManager, InjectionMember[]? injectionMembers = null)
{
Type = null;
Key = typeof(LifetimeManager);
Value = lifetimeManager;
LifetimeManager.InUse = true;
InjectionMembers = injectionMembers;
- Next = (PolicyEntry)validators;
+ Next = (PolicyEntry?)validators;
}
- public ExplicitRegistration(IPolicySet validators, Type mappedTo, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
+ public ExplicitRegistration(IPolicySet? validators, Type mappedTo, LifetimeManager lifetimeManager, InjectionMember[]? injectionMembers = null)
{
Type = mappedTo;
Key = typeof(LifetimeManager);
Value = lifetimeManager;
LifetimeManager.InUse = true;
InjectionMembers = injectionMembers;
- Next = (PolicyEntry)validators;
+ Next = (PolicyEntry?)validators;
}
#endregion
@@ -53,7 +53,7 @@ namespace Unity.Registration
/// The type that this registration is mapped to. If no type mapping was done, the
/// property and this one will have the same value.
///
- public Type Type { get; }
+ public Type? Type { get; }
#endregion
@@ -70,7 +70,7 @@ namespace Unity.Registration
_registration = set;
}
- public Type Type => _registration.Type;
+ public Type? Type => _registration.Type;
}
#endregion
diff --git a/src/Registration/ImplicitRegistration.cs b/src/Registration/ImplicitRegistration.cs
index 30e1f722..5f066513 100644
--- a/src/Registration/ImplicitRegistration.cs
+++ b/src/Registration/ImplicitRegistration.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Threading;
+using Unity.Composition;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Policy;
@@ -27,8 +28,8 @@ namespace Unity.Registration
{
}
- public ImplicitRegistration(IPolicySet set)
- : base(typeof(LifetimeManager), null, (PolicyEntry)set)
+ public ImplicitRegistration(IPolicySet? set)
+ : base(typeof(LifetimeManager), null, (PolicyEntry?)set)
{
}
@@ -41,16 +42,10 @@ namespace Unity.Registration
InjectionMembers = factory.InjectionMembers;
}
- public ImplicitRegistration(Type policyInterface, object policy)
+ public ImplicitRegistration(CompositionDelegate factory)
: base(typeof(LifetimeManager))
{
- Key = typeof(LifetimeManager);
- Next = new PolicyEntry
- {
- Key = policyInterface,
- Value = policy,
- Next = Next
- };
+ Factory = factory;
}
#endregion
@@ -58,17 +53,19 @@ namespace Unity.Registration
#region Public Members
- public virtual BuilderStrategy[] BuildChain { get; set; }
+ public virtual CompositionDelegate? Factory { get; set; }
- public InjectionMember[] InjectionMembers { get; set; }
+ public virtual BuilderStrategy[]? BuildChain { get; set; }
+
+ public InjectionMember[]? InjectionMembers { get; set; }
public bool BuildRequired { get; set; }
- public Converter Map { get; set; }
+ public Converter? Map { get; set; }
- public LifetimeManager LifetimeManager
+ public LifetimeManager? LifetimeManager
{
- get => (LifetimeManager)Value;
+ get => Value as LifetimeManager;
set => Value = value;
}
@@ -88,14 +85,25 @@ namespace Unity.Registration
#region IPolicySet
+ public override object? Get(Type policyInterface)
+ {
+ if (typeof(CompositionDelegate) == policyInterface)
+ return Factory;
+ else
+ return base.Get(policyInterface);
+ }
+
public override void Set(Type policyInterface, object policy)
{
- Next = new PolicyEntry
- {
- Key = policyInterface,
- Value = policy,
- Next = Next
- };
+ if (typeof(CompositionDelegate) == policyInterface)
+ Factory = (CompositionDelegate)policy;
+ else
+ Next = new PolicyEntry
+ {
+ Key = policyInterface,
+ Value = policy,
+ Next = Next
+ };
}
#endregion
@@ -113,13 +121,13 @@ namespace Unity.Registration
_registration = set;
}
- public InjectionMember[] InjectionMembers => _registration.InjectionMembers;
+ public InjectionMember[]? InjectionMembers => _registration.InjectionMembers;
public bool BuildRequired => _registration.BuildRequired;
- public Converter Map => _registration.Map;
+ public Converter? Map => _registration.Map;
- public LifetimeManager LifetimeManager => null;
+ public LifetimeManager? LifetimeManager => null;
public int RefCount => _registration._refCount;
}
diff --git a/src/Storage/PolicyEntry.cs b/src/Storage/PolicyEntry.cs
index d07bb358..b9d41230 100644
--- a/src/Storage/PolicyEntry.cs
+++ b/src/Storage/PolicyEntry.cs
@@ -4,8 +4,8 @@ namespace Unity.Storage
{
public class PolicyEntry
{
- public Type Key;
- public object Value;
- public PolicyEntry Next;
+ public Type? Key;
+ public object? Value;
+ public PolicyEntry? Next;
}
}
diff --git a/src/Storage/PolicySet.cs b/src/Storage/PolicySet.cs
index 351f8a70..090ac286 100644
--- a/src/Storage/PolicySet.cs
+++ b/src/Storage/PolicySet.cs
@@ -20,13 +20,13 @@ namespace Unity.Storage
Key = type;
}
- public PolicySet(Type type, object value)
+ public PolicySet(Type type, object? value)
{
Key = type;
Value = value;
}
- public PolicySet(Type type, object value, PolicyEntry set)
+ public PolicySet(Type type, object? value, PolicyEntry? set)
{
var node = (PolicyEntry)this;
node.Key = type;
@@ -39,9 +39,9 @@ namespace Unity.Storage
#region IPolicySet
- public virtual object Get(Type policyInterface)
+ public virtual object? Get(Type policyInterface)
{
- for (var node = (PolicyEntry)this; node != null; node = node.Next)
+ for (PolicyEntry? node = this; node != null; node = node.Next)
{
if (node.Key == policyInterface)
return node.Value;
@@ -52,7 +52,7 @@ namespace Unity.Storage
public virtual void Set(Type policyInterface, object policy)
{
- for (var node = (PolicyEntry)this; node != null; node = node.Next)
+ for (PolicyEntry? node = this; node != null; node = node.Next)
{
if (node.Key == policyInterface)
{
@@ -71,8 +71,8 @@ namespace Unity.Storage
public virtual void Clear(Type policyInterface)
{
- PolicyEntry node;
- PolicyEntry last = null;
+ PolicyEntry? node;
+ PolicyEntry? last = null;
for (node = this; node != null; node = node.Next)
{
@@ -104,7 +104,7 @@ namespace Unity.Storage
public IEnumerator GetEnumerator()
{
- for (var node = (PolicyEntry)this; node != null; node = node.Next)
+ for (PolicyEntry? node = this; node != null; node = node.Next)
yield return node;
}
@@ -120,7 +120,7 @@ namespace Unity.Storage
get
{
var count = 0;
- for (var node = (PolicyEntry)this; node != null; node = node.Next)
+ for (PolicyEntry? node = this; node != null; node = node.Next)
count += 1;
return count;
@@ -146,8 +146,8 @@ namespace Unity.Storage
{
PolicyEntry _node;
public Policy(PolicyEntry node) => _node = node;
- public Type Interface => _node.Key;
- public object Value => _node.Value;
+ public Type? Interface => _node.Key;
+ public object? Value => _node.Value;
}
#endregion
diff --git a/src/Storage/Registry.cs b/src/Storage/Registry.cs
index c39b6890..5431a700 100644
--- a/src/Storage/Registry.cs
+++ b/src/Storage/Registry.cs
@@ -19,7 +19,32 @@ namespace Unity.Storage
#region Constructors
- public Registry(int prime = 0)
+
+ public Registry()
+ {
+ var size = Primes[0];
+
+ Buckets = new int[size];
+ Entries = new Entry[size];
+ Count = 1;
+
+#if !NET40
+ unsafe
+ {
+ fixed (int* bucketsPtr = Buckets)
+ {
+ int* ptr = bucketsPtr;
+ var end = bucketsPtr + Buckets.Length;
+ while (ptr < end) *ptr++ = -1;
+ }
+ }
+#else
+ for(int i = 0; i < Buckets.Length; i++)
+ Buckets[i] = -1;
+#endif
+ }
+
+ public Registry(int prime)
{
if (prime < 0 || prime >= Primes.Length) throw new ArgumentException("Capacity Overflow");
diff --git a/src/Strategies/BuildKeyMappingStrategy.cs b/src/Strategies/BuildKeyMappingStrategy.cs
index 447443ca..a46076e0 100644
--- a/src/Strategies/BuildKeyMappingStrategy.cs
+++ b/src/Strategies/BuildKeyMappingStrategy.cs
@@ -4,6 +4,7 @@ using Unity.Builder;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Registration;
+using Unity.Resolution;
namespace Unity.Strategies
{
@@ -12,9 +13,38 @@ namespace Unity.Strategies
///
public class BuildKeyMappingStrategy : BuilderStrategy
{
+ #region Composition
+
+ public override ResolveDelegate? BuildResolver(UnityContainer container, Type type, ImplicitRegistration registration, ResolveDelegate? seed)
+ {
+ var required = registration is ExplicitRegistration explicitRegistration
+ ? RequiredToBuildType(container, type, registration, explicitRegistration.InjectionMembers)
+ : RequiredToBuildType(container, type, registration);
+
+ return !required ? seed :
+ (ref BuilderContext context) =>
+ {
+ var map = ((ImplicitRegistration)context.Registration).Map;
+ if (null != map && null != context.Type) context.Type = map(context.Type);
+
+ if (!((ImplicitRegistration)context.Registration).BuildRequired &&
+ ((UnityContainer)context.Container).IsRegistered(ref context) &&
+ null != context.Type)
+ {
+ return context.Resolve();
+ }
+
+ // Compose down the chain
+ return seed?.Invoke(ref context);
+ };
+ }
+
+ #endregion
+
+
#region Registration and Analysis
- public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[] injectionMembers)
+ public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[]? injectionMembers)
{
if (!(registration is ExplicitRegistration containerRegistration)) return null != registration.Map;
@@ -48,7 +78,7 @@ namespace Unity.Strategies
try
{
- return containerRegistration.Type.MakeGenericType(targetTypeInfo.GenericTypeArguments);
+ return containerRegistration.Type?.MakeGenericType(targetTypeInfo.GenericTypeArguments);
}
catch (ArgumentException ae)
{
@@ -73,13 +103,13 @@ namespace Unity.Strategies
public override void PreBuildUp(ref BuilderContext context)
{
var map = ((ImplicitRegistration)context.Registration).Map;
- if (null != map) context.Type = map(context.Type);
+ if (null != map && null != context.Type) context.Type = map(context.Type);
if (!((ImplicitRegistration)context.Registration).BuildRequired &&
- ((UnityContainer)context.Container).IsRegistered(ref context))
+ ((UnityContainer)context.Container).IsRegistered(ref context) &&
+ null != context.Type)
{
- // TODO: Optimize call, no need for parameters
- context.Existing = context.Resolve(context.Type, context.Name);
+ context.Existing = context.Resolve();
context.BuildComplete = true;
}
}
diff --git a/src/Strategies/BuildPlanStrategy.cs b/src/Strategies/BuildPlanStrategy.cs
index 337be7e4..b00fe3fd 100644
--- a/src/Strategies/BuildPlanStrategy.cs
+++ b/src/Strategies/BuildPlanStrategy.cs
@@ -17,9 +17,61 @@ namespace Unity.Strategies
///
public class BuildPlanStrategy : BuilderStrategy
{
+ #region Composition
+
+ public override ResolveDelegate? BuildResolver(UnityContainer container, Type type, ImplicitRegistration registration, ResolveDelegate? seed)
+ {
+ ResolveDelegate? storedResolver = null;
+
+ return (ref BuilderContext context) =>
+ {
+ var resolver = storedResolver ?? context.GetResolver();
+
+ if (null == resolver)
+ {
+ // Check if can be created
+ if (!(context.Registration is ExplicitRegistration) &&
+#if NETCOREAPP1_0 || NETSTANDARD1_0
+ context.RegistrationType.GetTypeInfo().IsGenericTypeDefinition)
+#else
+ context.RegistrationType.IsGenericTypeDefinition)
+#endif
+ {
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
+ "The type {0} is an open generic type. An open generic type cannot be resolved.",
+ context.RegistrationType.FullName));
+ }
+
+ // Get resolver factory
+ var factory = context.GetFactory();
+
+ // Create plan
+ if (null != factory)
+ {
+ storedResolver = factory(ref context);
+
+ context.Registration.Set(typeof(ResolveDelegate), storedResolver);
+ context.Existing = storedResolver(ref context);
+ }
+ else
+ throw new ResolutionFailedException(context.Type, context.Name, $"Failed to find Resolve Delegate Factory for Type {context.Type}");
+ }
+ else
+ {
+ // Plan has been already created, just build the object
+ context.Existing = resolver(ref context);
+ }
+
+ return null == seed ? context.Existing : seed(ref context);
+ };
+ }
+
+ #endregion
+
+
#region Registration and Analysis
- public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[] injectionMembers)
+ public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[]? injectionMembers)
{
// Require Re-Resolve if no injectors specified
registration.BuildRequired = (injectionMembers?.Any(m => m.BuildRequired) ?? false) ||
diff --git a/src/Strategies/LifetimeStrategy.cs b/src/Strategies/LifetimeStrategy.cs
index 007eeb81..14a3fb61 100644
--- a/src/Strategies/LifetimeStrategy.cs
+++ b/src/Strategies/LifetimeStrategy.cs
@@ -1,9 +1,11 @@
using System;
using System.Reflection;
using Unity.Builder;
+using Unity.Composition;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Registration;
+using Unity.Resolution;
namespace Unity.Strategies
{
@@ -22,11 +24,37 @@ namespace Unity.Strategies
#endregion
+ #region Composition
+
+ public override ResolveDelegate? BuildResolver(UnityContainer container, Type type, ImplicitRegistration registration, ResolveDelegate? seed)
+ {
+ var lifetime = registration.LifetimeManager;
+
+ if (null == lifetime || lifetime is TransientLifetimeManager) return seed;
+
+ return (ref BuilderContext context) =>
+ {
+ // Return if holds value
+ var value = lifetime.GetValue(context.Lifetime);
+ if (LifetimeManager.NoValue != value) return value;
+
+ // Compose down the chain
+ value = seed?.Invoke(ref context);
+ lifetime.SetValue(value, context.Lifetime);
+
+ return value;
+ };
+ }
+
+
+ #endregion
+
+
#region Build
public override void PreBuildUp(ref BuilderContext context)
{
- LifetimeManager policy = null;
+ LifetimeManager? policy = null;
if (context.Registration is ImplicitRegistration registration)
policy = registration.LifetimeManager;
@@ -49,7 +77,7 @@ namespace Unity.Strategies
public override void PostBuildUp(ref BuilderContext context)
{
- LifetimeManager policy = null;
+ LifetimeManager? policy = null;
if (context.Registration is ImplicitRegistration registration)
policy = registration.LifetimeManager;
@@ -65,7 +93,7 @@ namespace Unity.Strategies
#region Registration and Analysis
- public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[] injectionMembers)
+ public override bool RequiredToBuildType(IUnityContainer container, Type type, ImplicitRegistration registration, params InjectionMember[]? injectionMembers)
{
var policy = registration.LifetimeManager;
if (null != policy)
diff --git a/src/Unity.Container.csproj b/src/Unity.Container.csproj
index fab13105..06557c29 100644
--- a/src/Unity.Container.csproj
+++ b/src/Unity.Container.csproj
@@ -22,8 +22,9 @@
false
Unity
Unity Container unitycontainer Microsoft.Practices.Unity IoC
- latest
true
+ 8.0
+ enable
diff --git a/src/UnityContainer.Composition.cs b/src/UnityContainer.Composition.cs
new file mode 100644
index 00000000..18026b92
--- /dev/null
+++ b/src/UnityContainer.Composition.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using Unity.Builder;
+using Unity.Composition;
+using Unity.Registration;
+using Unity.Resolution;
+using Unity.Storage;
+using Unity.Strategies;
+
+namespace Unity
+{
+ public partial class UnityContainer
+ {
+ internal delegate CompositionDelegate CompositionFactoryDelegate(ref CompositionContext context);
+
+ #region Fields
+
+ internal CompositionFactoryDelegate _factory = ResolvedComposition;
+
+ #endregion
+
+
+
+ #region Composition
+
+ private object? Compose(Type type, string? name, params ResolverOverride[] overrides)
+ {
+ var registration = GetRegistration(type, name);
+
+ // Double-check lock
+ lock (registration)
+ {
+ // Make sure build plan was not yet created
+ if (null == registration.Factory)
+ {
+ // Create build plan
+ var context = new CompositionContext
+ {
+ Type = type,
+ Name = name,
+ Overrides = overrides,
+ Registration = registration,
+ Container = this,
+ };
+
+ registration.Factory = _factory.Invoke(ref context);
+ }
+ }
+
+ // Execute the plan
+ return registration.Factory.Invoke(this, null, overrides);
+ }
+
+ #endregion
+
+
+ #region Build Plan
+
+
+ internal static CompositionDelegate CompiledComposition(ref CompositionContext context)
+ {
+ var expressions = new List();
+ //var type = context.Type;
+ //var registration = context.Registration;
+
+ //foreach (var processor in _processorsChain)
+ //{
+ // foreach (var step in processor.GetExpressions(type, registration))
+ // expressions.Add(step);
+ //}
+
+ expressions.Add(BuilderContextExpression.Existing);
+
+ var lambda = Expression.Lambda(
+ Expression.Block(expressions), BuilderContextExpression.Context);
+
+ return lambda.Compile();
+ }
+
+ internal static CompositionDelegate ResolvedComposition(ref CompositionContext context)
+ {
+ // Closures
+ ResolveDelegate? seedMethod = null;
+
+ var type = context.Type;
+ var name = context.Name;
+ var overrides = context.Overrides;
+ var registration = context.Registration;
+ var typeMapped = registration is ExplicitRegistration containerRegistration
+ ? containerRegistration.Type : context.Type;
+
+ // Build chain
+ foreach (var strategy in registration?.BuildChain ?? throw new ArgumentNullException(nameof(registration.BuildChain)))
+ seedMethod = strategy.BuildResolver(context.Container, type, registration, seedMethod);
+
+ // Assemble composer
+ return (null == seedMethod)
+ ? (CompositionDelegate)((c, e, o) => null)
+ : ((UnityContainer container, object? existing, ResolverOverride[] overrides) =>
+ {
+ var context = new BuilderContext
+ {
+ RegistrationType = type,
+ Name = name,
+ Type = typeMapped,
+ Registration = registration,
+ Lifetime = container.LifetimeContainer,
+ Overrides = null != overrides && 0 == overrides.Length ? null : overrides,
+
+ List = new PolicyList(),
+ ExecutePlan = container.ContextExecutePlan,
+ ResolvePlan = container.ContextResolvePlan,
+ };
+
+ return seedMethod(ref context);
+ });
+ }
+
+
+ #endregion
+ }
+}
diff --git a/src/UnityContainer.ContainerContext.cs b/src/UnityContainer.ContainerContext.cs
index db03a1ba..14c05e89 100644
--- a/src/UnityContainer.ContainerContext.cs
+++ b/src/UnityContainer.ContainerContext.cs
@@ -89,10 +89,10 @@ namespace Unity
#region IPolicyList
- public virtual object Get(Type type, Type policyInterface)
+ public virtual object? Get(Type type, Type policyInterface)
=> _container.GetPolicy(type, policyInterface);
- public virtual object Get(Type type, string name, Type policyInterface)
+ public virtual object? Get(Type type, string name, Type policyInterface)
=> _container.GetPolicy(type, name, policyInterface);
public virtual void Set(Type type, Type policyInterface, object policy)
diff --git a/src/UnityContainer.IUnityContainer.cs b/src/UnityContainer.IUnityContainer.cs
index b1b8991f..720c8400 100644
--- a/src/UnityContainer.IUnityContainer.cs
+++ b/src/UnityContainer.IUnityContainer.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Unity.Builder;
+using Unity.Composition;
using Unity.Events;
using Unity.Injection;
using Unity.Lifetime;
@@ -108,7 +109,7 @@ namespace Unity
#region Instance Registration
///
- IUnityContainer IUnityContainer.RegisterInstance(Type type, string name, object instance, IInstanceLifetimeManager lifetimeManager)
+ IUnityContainer IUnityContainer.RegisterInstance(Type type, string? name, object instance, IInstanceLifetimeManager lifetimeManager)
{
var mappedToType = instance?.GetType();
var registeredType = type ?? mappedToType;
@@ -124,7 +125,7 @@ namespace Unity
// Create registration and add to appropriate storage
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
- var registration = new ExplicitRegistration(null, mappedToType, ((LifetimeManager)lifetimeManager));
+ var registration = new ExplicitRegistration(null, mappedToType, (LifetimeManager)lifetimeManager);
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable manager)
@@ -134,7 +135,7 @@ namespace Unity
var previous = container.Register(registeredType, name, registration);
// Allow reference adjustment and disposal
- if (null != previous && 0 == previous.Release()
+ if (null != previous && 0 == previous.Release()
&& previous.LifetimeManager is IDisposable disposable)
{
// Dispose replaced lifetime manager
@@ -223,12 +224,8 @@ namespace Unity
#region Getting objects
///
- object IUnityContainer.Resolve(Type type, string name, params ResolverOverride[] overrides)
+ object IUnityContainer.Resolve(Type type, string? name, params ResolverOverride[] overrides)
{
- // Verify arguments
- if (null == type) throw new ArgumentNullException(nameof(type));
- name = string.IsNullOrEmpty(name) ? null : name;
-
var registration = GetRegistration(type, name);
var context = new BuilderContext
{
@@ -253,7 +250,7 @@ namespace Unity
#region BuildUp existing object
///
- object IUnityContainer.BuildUp(Type type, object existing, string name, params ResolverOverride[] overrides)
+ public object BuildUp(Type type, object existing, string? name, params ResolverOverride[] overrides)
{
// Verify arguments
if (null == type) throw new ArgumentNullException(nameof(type));
@@ -286,12 +283,7 @@ namespace Unity
#region Child container management
///
- IUnityContainer IUnityContainer.CreateChildContainer()
- {
- var child = new UnityContainer(this);
- ChildContainerCreated?.Invoke(this, new ChildContainerCreatedEventArgs(child._context));
- return child;
- }
+ IUnityContainer IUnityContainer.CreateChildContainer() => CreateChildContainer();
///
IUnityContainer IUnityContainer.Parent => _parent;
diff --git a/src/UnityContainer.IUnityContainerAsync.cs b/src/UnityContainer.IUnityContainerAsync.cs
index eeaef9e6..7ce01137 100644
--- a/src/UnityContainer.IUnityContainerAsync.cs
+++ b/src/UnityContainer.IUnityContainerAsync.cs
@@ -3,14 +3,17 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using Unity.Composition;
+using Unity.Events;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Registration;
using Unity.Resolution;
-using Unity.Storage;
+
namespace Unity
{
+
public partial class UnityContainer : IUnityContainerAsync
{
#region Registration
@@ -18,7 +21,7 @@ namespace Unity
#region Type
///
- IUnityContainer IUnityContainerAsync.RegisterType(IEnumerable interfaces, Type type, string name, ITypeLifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
+ IUnityContainerAsync IUnityContainerAsync.RegisterType(IEnumerable interfaces, Type type, string name, ITypeLifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
{
throw new NotImplementedException();
}
@@ -29,7 +32,7 @@ namespace Unity
#region Factory
///
- IUnityContainer IUnityContainerAsync.RegisterFactory(IEnumerable interfaces, string name, Func factory, IFactoryLifetimeManager lifetimeManager)
+ IUnityContainerAsync IUnityContainerAsync.RegisterFactory(IEnumerable interfaces, string name, Func factory, IFactoryLifetimeManager lifetimeManager)
{
// Validate input
// TODO: Move to diagnostic
@@ -85,7 +88,7 @@ namespace Unity
#region Instance
///
- IUnityContainer IUnityContainerAsync.RegisterInstance(IEnumerable interfaces, string name, object instance, IInstanceLifetimeManager lifetimeManager)
+ IUnityContainerAsync IUnityContainerAsync.RegisterInstance(IEnumerable interfaces, string name, object instance, IInstanceLifetimeManager lifetimeManager)
{
// Validate input
// TODO: Move to diagnostic
@@ -135,33 +138,70 @@ namespace Unity
#endregion
- #region Hierarchy
-
- ///
- IUnityContainer IUnityContainerAsync.Parent => throw new NotImplementedException();
-
- ///
- IUnityContainer IUnityContainerAsync.CreateChildContainer()
- {
- throw new NotImplementedException();
- }
-
- #endregion
-
-
#region Resolution
+
+
///
- Task