Changing registrations engine
This commit is contained in:
Родитель
ec39834140
Коммит
9ad7e68bee
|
@ -0,0 +1,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity.Abstracts
|
||||
{
|
||||
public delegate Task<object> PipelineDelegate(IUnityContainer container, params ResolverOverride[] overrides);
|
||||
}
|
|
@ -11,6 +11,27 @@ namespace Unity.Registration
|
|||
{
|
||||
#region Constructors
|
||||
|
||||
public ContainerRegistration(Type mappedTo, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
|
||||
{
|
||||
Type = mappedTo;
|
||||
Key = typeof(LifetimeManager);
|
||||
Value = lifetimeManager;
|
||||
LifetimeManager.InUse = true;
|
||||
InjectionMembers = injectionMembers;
|
||||
Next = null;
|
||||
}
|
||||
|
||||
|
||||
public ContainerRegistration(LinkedNode<Type, object> validators, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
|
||||
{
|
||||
Type = null;
|
||||
Key = typeof(LifetimeManager);
|
||||
Value = lifetimeManager;
|
||||
LifetimeManager.InUse = true;
|
||||
InjectionMembers = injectionMembers;
|
||||
Next = validators;
|
||||
}
|
||||
|
||||
public ContainerRegistration(LinkedNode<Type, object> validators, Type mappedTo, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers = null)
|
||||
{
|
||||
Type = mappedTo;
|
||||
|
@ -32,13 +53,6 @@ namespace Unity.Registration
|
|||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The lifetime manager for this registration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property will be null if this registration is for an open generic.</remarks>
|
||||
public LifetimeManager LifetimeManager => (LifetimeManager)Value;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Unity.Injection;
|
||||
using Unity.Lifetime;
|
||||
using Unity.Policy;
|
||||
using Unity.Storage;
|
||||
using Unity.Strategies;
|
||||
|
@ -11,16 +13,28 @@ namespace Unity.Registration
|
|||
public class InternalRegistration : LinkedNode<Type, object>,
|
||||
IPolicySet
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private int _refCount;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public InternalRegistration()
|
||||
{
|
||||
Key = typeof(LifetimeManager);
|
||||
}
|
||||
|
||||
public InternalRegistration(Type policyInterface, object policy)
|
||||
{
|
||||
Key = policyInterface;
|
||||
Value = policy;
|
||||
Key = typeof(LifetimeManager);
|
||||
Next = new LinkedNode<Type, object>
|
||||
{
|
||||
Key = policyInterface,
|
||||
Value = policy,
|
||||
Next = Next
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -36,6 +50,17 @@ namespace Unity.Registration
|
|||
|
||||
public Converter<Type, Type> Map { get; set; }
|
||||
|
||||
// TODO: Streamline LifetimeManager usage
|
||||
public LifetimeManager LifetimeManager
|
||||
{
|
||||
get => (LifetimeManager)Value;
|
||||
set => Value = value;
|
||||
}
|
||||
|
||||
public virtual int AddRef() => Interlocked.Increment(ref _refCount);
|
||||
|
||||
public virtual int Release() => Interlocked.Decrement(ref _refCount);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
@ -54,20 +79,12 @@ namespace Unity.Registration
|
|||
|
||||
public virtual void Set(Type policyInterface, object policy)
|
||||
{
|
||||
if (null == Value && null == Key)
|
||||
Next = new LinkedNode<Type, object>
|
||||
{
|
||||
Key = policyInterface;
|
||||
Value = policy;
|
||||
}
|
||||
else
|
||||
{
|
||||
Next = new LinkedNode<Type, object>
|
||||
{
|
||||
Key = policyInterface,
|
||||
Value = policy,
|
||||
Next = Next
|
||||
};
|
||||
}
|
||||
Key = policyInterface,
|
||||
Value = policy,
|
||||
Next = Next
|
||||
};
|
||||
}
|
||||
|
||||
public virtual void Clear(Type policyInterface)
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Unity.Utility;
|
||||
|
||||
namespace Unity.Storage
|
||||
{
|
||||
[DebuggerDisplay("Metadata ({Count}) ")]
|
||||
internal class Metadata
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private int[] Buckets;
|
||||
private Entry[] Entries;
|
||||
private int Count;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Metadata()
|
||||
{
|
||||
Buckets = new int[37];
|
||||
Entries = new Entry[37];
|
||||
|
||||
HashHelpers.FillArray(Buckets, -1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Members
|
||||
|
||||
public void Add(Type key, int value)
|
||||
{
|
||||
// Check for existing
|
||||
var hashCode = (key?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||
var targetBucket = hashCode % Buckets.Length;
|
||||
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
|
||||
{
|
||||
ref var candidate = ref Entries[i];
|
||||
if (candidate.HashCode != hashCode || !Equals(candidate.Key, key)) continue;
|
||||
|
||||
if (candidate.Data.Length == candidate.Count)
|
||||
{
|
||||
var source = candidate.Data;
|
||||
candidate.Data = new int[2 * candidate.Data.Length];
|
||||
Array.Copy(source, 0, candidate.Data, 0, candidate.Count);
|
||||
}
|
||||
|
||||
candidate.Data[candidate.Count++] = value;
|
||||
}
|
||||
|
||||
// Grow if required
|
||||
if ((Entries.Length - Count) < 100 && (float)Count / Entries.Length > 0.72f)
|
||||
{
|
||||
var entries = Entries;
|
||||
var size = HashHelpers.GetPrime(2 * Buckets.Length);
|
||||
|
||||
Buckets = new int[size];
|
||||
Entries = new Entry[size];
|
||||
|
||||
HashHelpers.FillArray(Buckets, -1);
|
||||
|
||||
Array.Copy(entries, 0, Entries, 0, Count);
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
var hash = Entries[i].HashCode;
|
||||
if (hashCode < 0) continue;
|
||||
|
||||
var bucket = hash % Buckets.Length;
|
||||
Entries[i].Next = Buckets[bucket];
|
||||
Buckets[bucket] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new entry
|
||||
ref var entry = ref Entries[Count];
|
||||
entry.HashCode = hashCode;
|
||||
entry.Next = Buckets[targetBucket];
|
||||
entry.Key = key;
|
||||
entry.Count = 1;
|
||||
entry.Data = new int[] { value, -1 };
|
||||
Buckets[targetBucket] = Count++;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Nested Types
|
||||
|
||||
[DebuggerDisplay("Type='{Key}' Registrations='{Count}'")]
|
||||
public struct Entry
|
||||
{
|
||||
public int HashCode;
|
||||
public int Next;
|
||||
public Type Key;
|
||||
public int Count;
|
||||
public int[] Data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ using Unity.Utility;
|
|||
|
||||
namespace Unity.Storage
|
||||
{
|
||||
[SecuritySafeCritical]
|
||||
[DebuggerDisplay("Registrations ({Count}) ")]
|
||||
internal class Registrations : IRegistry<Type, IRegistry<string, IPolicySet>>
|
||||
{
|
||||
|
@ -32,23 +31,11 @@ namespace Unity.Storage
|
|||
public Registrations(int capacity)
|
||||
{
|
||||
var size = HashHelpers.GetPrime(capacity);
|
||||
|
||||
Buckets = new int[size];
|
||||
Entries = new Entry[size];
|
||||
|
||||
#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
|
||||
HashHelpers.FillArray(Buckets, -1);
|
||||
}
|
||||
|
||||
public Registrations(int capacity, LinkedNode<Type, IRegistry<string, IPolicySet>> head)
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using Unity.Policy;
|
||||
using Unity.Resolution;
|
||||
using Unity.Utility;
|
||||
|
||||
namespace Unity.Storage
|
||||
{
|
||||
public class Registry
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public readonly int[] Buckets;
|
||||
public readonly Entry[] Entries;
|
||||
public int Count;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Registry(int capacity = 37)
|
||||
{
|
||||
var size = HashHelpers.GetPrime(capacity);
|
||||
|
||||
Buckets = new int[size];
|
||||
Entries = new Entry[size];
|
||||
|
||||
HashHelpers.FillArray(Buckets, -1);
|
||||
}
|
||||
|
||||
public Registry(Registry registry)
|
||||
: this(HashHelpers.GetPrime(registry.Entries.Length * 2))
|
||||
{
|
||||
Array.Copy(registry.Entries, 0, Entries, 0, registry.Count);
|
||||
for (var i = 0; i < registry.Count; i++)
|
||||
{
|
||||
var hashCode = Entries[i].HashCode;
|
||||
if (hashCode < 0) continue;
|
||||
|
||||
var bucket = hashCode % Buckets.Length;
|
||||
Entries[i].Next = Buckets[bucket];
|
||||
Buckets[bucket] = i;
|
||||
}
|
||||
Count = registry.Count;
|
||||
registry.Count = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
|
||||
(float)Count / Entries.Length > 0.72f;
|
||||
|
||||
|
||||
#region Nested Types
|
||||
|
||||
public struct Entry
|
||||
{
|
||||
public int HashCode;
|
||||
public NamedType Key;
|
||||
public int Next;
|
||||
public IPolicySet Reference;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -28,38 +28,13 @@ namespace Unity.Strategies
|
|||
{
|
||||
LifetimeManager policy = null;
|
||||
|
||||
if (context.Registration is ContainerRegistration registration)
|
||||
if (context.Registration is InternalRegistration registration)
|
||||
policy = registration.LifetimeManager;
|
||||
|
||||
if (null == policy || policy is PerResolveLifetimeManager)
|
||||
policy = (LifetimeManager)context.Get(typeof(LifetimeManager));
|
||||
if (null == policy)
|
||||
{
|
||||
#if NETSTANDARD1_0 || NETCOREAPP1_0
|
||||
if (!context.RegistrationType.GetTypeInfo().IsGenericType) return;
|
||||
#else
|
||||
if (!context.RegistrationType.IsGenericType) return;
|
||||
#endif
|
||||
var manager = (LifetimeManager)context.Get(context.Type.GetGenericTypeDefinition(),
|
||||
context.Name, typeof(LifetimeManager));
|
||||
if (null == manager) return;
|
||||
|
||||
lock (_genericLifetimeManagerLock)
|
||||
{
|
||||
// check whether the policy for closed-generic has been added since first checked
|
||||
policy = (LifetimeManager)context.Registration.Get(typeof(LifetimeManager));
|
||||
if (null == policy)
|
||||
{
|
||||
policy = manager.CreateLifetimePolicy();
|
||||
context.Registration.Set(typeof(LifetimeManager), policy);
|
||||
|
||||
if (policy is IDisposable)
|
||||
{
|
||||
context.Lifetime.Add(policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (null == policy) return;
|
||||
|
||||
if (policy is SynchronizedLifetimeManager recoveryPolicy)
|
||||
context.RequiresRecovery = recoveryPolicy;
|
||||
|
@ -76,7 +51,7 @@ namespace Unity.Strategies
|
|||
{
|
||||
LifetimeManager policy = null;
|
||||
|
||||
if (context.Registration is ContainerRegistration registration)
|
||||
if (context.Registration is InternalRegistration registration)
|
||||
policy = registration.LifetimeManager;
|
||||
|
||||
if (null == policy || policy is PerResolveLifetimeManager)
|
||||
|
@ -92,7 +67,7 @@ namespace Unity.Strategies
|
|||
|
||||
public override bool RequiredToBuildType(IUnityContainer container, Type type, InternalRegistration registration, params InjectionMember[] injectionMembers)
|
||||
{
|
||||
var policy = registration.Get(typeof(LifetimeManager));
|
||||
var policy = registration.LifetimeManager;
|
||||
if (null != policy)
|
||||
{
|
||||
return policy is TransientLifetimeManager ? false : true;
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Unity
|
|||
var registration = new ContainerRegistration(_validators, typeTo, (LifetimeManager)lifetimeManager, injectionMembers);
|
||||
|
||||
// Add or replace existing
|
||||
var previous = container.Register(registeredType, name, registration);
|
||||
var previous = container.RegisterLegacy(registeredType, name, registration);
|
||||
if (previous is ContainerRegistration old &&
|
||||
old.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ namespace Unity
|
|||
var registration = new ContainerRegistration(null, mappedToType, ((LifetimeManager)lifetimeManager));
|
||||
|
||||
// Add or replace existing
|
||||
var previous = container.Register(typeFrom, name, registration);
|
||||
var previous = container.RegisterLegacy(typeFrom, name, registration);
|
||||
if (previous is ContainerRegistration old &&
|
||||
old.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
|
@ -183,7 +183,7 @@ namespace Unity
|
|||
var registration = new ContainerRegistration(_validators, type, ((LifetimeManager)lifetimeManager), injectionMembers);
|
||||
|
||||
// Add or replace existing
|
||||
var previous = container.Register(type, name, registration);
|
||||
var previous = container.RegisterLegacy(type, name, registration);
|
||||
if (previous is ContainerRegistration old &&
|
||||
old.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.Injection;
|
||||
using Unity.Lifetime;
|
||||
using Unity.Registration;
|
||||
using Unity.Resolution;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public partial class UnityContainer : IUnityContainerAsync
|
||||
{
|
||||
#region Registration
|
||||
|
||||
#region Type
|
||||
|
||||
/// <inheritdoc />
|
||||
IUnityContainer IUnityContainerAsync.RegisterType(IEnumerable<Type> interfaces, Type type, string name, ITypeLifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Factory
|
||||
|
||||
/// <inheritdoc />
|
||||
IUnityContainer IUnityContainerAsync.RegisterFactory(IEnumerable<Type> interfaces, string name, Func<IUnityContainer, Type, string, object> factory, IFactoryLifetimeManager lifetimeManager)
|
||||
{
|
||||
// Validate input
|
||||
// TODO: Move to diagnostic
|
||||
|
||||
if (null == interfaces) throw new ArgumentNullException(nameof(interfaces));
|
||||
if (null == factory) throw new ArgumentNullException(nameof(factory));
|
||||
if (null == lifetimeManager) lifetimeManager = TransientLifetimeManager.Instance;
|
||||
if (((LifetimeManager)lifetimeManager).InUse) throw new InvalidOperationException(LifetimeManagerInUse);
|
||||
|
||||
// Create registration and add to appropriate storage
|
||||
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
|
||||
|
||||
// TODO: InjectionFactory
|
||||
#pragma warning disable CS0618
|
||||
var injectionFactory = new InjectionFactory(factory);
|
||||
#pragma warning restore CS0618
|
||||
|
||||
var injectionMembers = new InjectionMember[] { injectionFactory };
|
||||
var registration = new ContainerRegistration(_validators, (LifetimeManager)lifetimeManager, injectionMembers);
|
||||
|
||||
// Add Injection Members
|
||||
//injectionFactory.AddPolicies<BuilderContext, ContainerRegistration>(
|
||||
// type, type, name, ref registration);
|
||||
|
||||
// Register interfaces
|
||||
var replaced = container.AddOrReplaceRegistrations(interfaces, name, registration)
|
||||
.ToArray();
|
||||
|
||||
// Release replaced registrations
|
||||
if (0 != replaced.Length)
|
||||
{
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
foreach (InternalRegistration previous in replaced)
|
||||
{
|
||||
if (0 == previous.Release() && previous.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
// Dispose replaced lifetime manager
|
||||
container.LifetimeContainer.Remove(disposable);
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Instance
|
||||
|
||||
/// <inheritdoc />
|
||||
IUnityContainer IUnityContainerAsync.RegisterInstance(IEnumerable<Type> interfaces, string name, object instance, IInstanceLifetimeManager lifetimeManager)
|
||||
{
|
||||
// Validate input
|
||||
// TODO: Move to diagnostic
|
||||
|
||||
if (null == interfaces && null == instance) throw new ArgumentNullException(nameof(interfaces));
|
||||
|
||||
// Validate lifetime manager
|
||||
if (null == lifetimeManager) lifetimeManager = new ContainerControlledLifetimeManager();
|
||||
if (((LifetimeManager)lifetimeManager).InUse) throw new InvalidOperationException(LifetimeManagerInUse);
|
||||
((LifetimeManager)lifetimeManager).SetValue(instance, LifetimeContainer);
|
||||
|
||||
// Create registration and add to appropriate storage
|
||||
var mappedToType = instance?.GetType();
|
||||
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
|
||||
var registration = new ContainerRegistration(mappedToType, (LifetimeManager)lifetimeManager);
|
||||
|
||||
// Register interfaces
|
||||
var replaced = container.AddOrReplaceRegistrations(interfaces, name, registration)
|
||||
.ToArray();
|
||||
|
||||
// Release replaced registrations
|
||||
if (0 != replaced.Length)
|
||||
{
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
foreach (InternalRegistration previous in replaced)
|
||||
{
|
||||
if (0 == previous.Release() && previous.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
// Dispose replaced lifetime manager
|
||||
container.LifetimeContainer.Remove(disposable);
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Registrations
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerable<IContainerRegistration> IUnityContainerAsync.Registrations
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
bool IUnityContainerAsync.IsRegistered(Type type, string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Hierarchy
|
||||
|
||||
/// <inheritdoc />
|
||||
IUnityContainer IUnityContainerAsync.Parent => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
IUnityContainer IUnityContainerAsync.CreateChildContainer()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolution
|
||||
|
||||
/// <inheritdoc />
|
||||
Task<object> IUnityContainerAsync.Resolve(Type type, string name, params ResolverOverride[] overrides)
|
||||
{
|
||||
return null;// _getPipeline(type, name).Invoke(this, overrides);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ namespace Unity
|
|||
internal Func<Type, string, IPolicySet> GetRegistration;
|
||||
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||
internal Func<Type, string, InternalRegistration, IPolicySet> Register;
|
||||
internal Func<Type, string, InternalRegistration, IPolicySet> RegisterLegacy;
|
||||
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||
internal GetPolicyDelegate GetPolicy;
|
||||
|
@ -98,6 +98,8 @@ namespace Unity
|
|||
_root = _parent._root;
|
||||
SetDefaultPolicies = parent.SetDefaultPolicies;
|
||||
|
||||
// Registry
|
||||
|
||||
// Methods
|
||||
_get = _parent._get;
|
||||
_getGenericRegistration = _parent._getGenericRegistration;
|
||||
|
@ -105,7 +107,7 @@ namespace Unity
|
|||
IsTypeExplicitlyRegistered = _parent.IsTypeExplicitlyRegistered;
|
||||
|
||||
GetRegistration = _parent.GetRegistration;
|
||||
Register = CreateAndSetOrUpdate;
|
||||
RegisterLegacy = CreateAndSetOrUpdate;
|
||||
GetPolicy = parent.GetPolicy;
|
||||
SetPolicy = CreateAndSetPolicy;
|
||||
ClearPolicy = delegate { };
|
||||
|
@ -242,7 +244,7 @@ namespace Unity
|
|||
SetupChildContainerBehaviors();
|
||||
}
|
||||
|
||||
return AddOrUpdate(type, name, registration);
|
||||
return AddOrUpdateLegacy(type, name, registration);
|
||||
}
|
||||
|
||||
private void SetupChildContainerBehaviors()
|
||||
|
@ -254,7 +256,7 @@ namespace Unity
|
|||
_registrations = new Registrations(ContainerInitialCapacity);
|
||||
Set(null, null, Defaults);
|
||||
|
||||
Register = AddOrUpdate;
|
||||
RegisterLegacy = AddOrUpdateLegacy;
|
||||
GetPolicy = Get;
|
||||
SetPolicy = Set;
|
||||
ClearPolicy = Clear;
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace Unity
|
|||
// Context
|
||||
_context = new ContainerContext(this);
|
||||
|
||||
// Registry
|
||||
Register = InitAndAdd;
|
||||
|
||||
// Methods
|
||||
_get = Get;
|
||||
_getGenericRegistration = GetOrAddGeneric;
|
||||
|
@ -39,7 +42,7 @@ namespace Unity
|
|||
IsTypeExplicitlyRegistered = IsTypeTypeExplicitlyRegisteredLocally;
|
||||
|
||||
GetRegistration = GetOrAdd;
|
||||
Register = AddOrUpdate;
|
||||
RegisterLegacy = AddOrUpdateLegacy;
|
||||
GetPolicy = Get;
|
||||
SetPolicy = Set;
|
||||
ClearPolicy = Clear;
|
||||
|
@ -78,6 +81,7 @@ namespace Unity
|
|||
|
||||
// Register this instance
|
||||
((IUnityContainer)this).RegisterInstance(typeof(IUnityContainer), null, this, new ContainerLifetimeManager());
|
||||
((IUnityContainerAsync)this).RegisterInstance(new[] { typeof(IUnityContainer) }, null, this, new ContainerLifetimeManager());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Unity.Policy;
|
||||
using Unity.Registration;
|
||||
using Unity.Resolution;
|
||||
using Unity.Storage;
|
||||
|
||||
namespace Unity
|
||||
|
@ -19,8 +21,19 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Delegates
|
||||
|
||||
private delegate IPolicySet RegisterDelegate(ref NamedType key, InternalRegistration registration);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Registration Fields
|
||||
|
||||
// Register single type
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||
private RegisterDelegate Register;
|
||||
|
||||
internal IPolicySet Defaults;
|
||||
private readonly object _syncRoot = new object();
|
||||
private LinkedNode<Type, object> _validators;
|
||||
|
@ -339,9 +352,112 @@ namespace Unity
|
|||
#endregion
|
||||
|
||||
|
||||
#region Dynamic Registrations
|
||||
|
||||
private IPolicySet GetDynamicRegistration(Type type, string name)
|
||||
{
|
||||
var registration = _get(type, name);
|
||||
if (null != registration) return registration;
|
||||
|
||||
var info = type.GetTypeInfo();
|
||||
return !info.IsGenericType
|
||||
? _root.GetOrAdd(type, name)
|
||||
: GetOrAddGeneric(type, name, info.GetGenericTypeDefinition());
|
||||
}
|
||||
|
||||
private IPolicySet CreateRegistration(Type type, string name)
|
||||
{
|
||||
var registration = new InternalRegistration(type, name);
|
||||
|
||||
if (type.GetTypeInfo().IsGenericType)
|
||||
{
|
||||
var factory = (InternalRegistration)_get(type.GetGenericTypeDefinition(), name);
|
||||
if (null != factory)
|
||||
{
|
||||
registration.InjectionMembers = factory.InjectionMembers;
|
||||
registration.Map = factory.Map;
|
||||
var manager = factory.LifetimeManager;
|
||||
if (null != manager)
|
||||
{
|
||||
var policy = manager.CreateLifetimePolicy();
|
||||
registration.LifetimeManager = policy;
|
||||
if (policy is IDisposable) LifetimeContainer.Add(policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registration.BuildChain = GetBuilders(type, registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
private IPolicySet CreateRegistration(Type type, Type policyInterface, object policy)
|
||||
{
|
||||
var registration = new InternalRegistration(policyInterface, policy);
|
||||
registration.BuildChain = GetBuilders(type, registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Registration manipulation
|
||||
|
||||
private IPolicySet AddOrUpdate(Type type, string name, InternalRegistration registration)
|
||||
private IEnumerable<IPolicySet> AddOrReplaceRegistrations(IEnumerable<Type> interfaces, string name, ContainerRegistration registration)
|
||||
{
|
||||
NamedType key;
|
||||
int count = 0;
|
||||
|
||||
key.Name = name;
|
||||
|
||||
if (null != interfaces)
|
||||
{
|
||||
foreach (var type in interfaces)
|
||||
{
|
||||
// Type to register
|
||||
key.Type = type;
|
||||
|
||||
// Add or replace existing
|
||||
var previous = Register(ref key, registration);
|
||||
|
||||
// Add reference count
|
||||
registration.AddRef();
|
||||
|
||||
// Allow reference adjustment and disposal
|
||||
if (previous is ContainerRegistration old &&
|
||||
old.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
yield return previous;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == count)
|
||||
{
|
||||
// TODO: Move to diagnostic
|
||||
if (null == registration.Type) throw new ArgumentNullException(nameof(interfaces));
|
||||
|
||||
// Type to register
|
||||
key.Type = registration.Type;
|
||||
|
||||
// Add or replace existing
|
||||
var previous = Register(ref key, registration);
|
||||
|
||||
// Add reference count
|
||||
registration.AddRef();
|
||||
|
||||
// Allow reference adjustment and disposal
|
||||
if (previous is ContainerRegistration old &&
|
||||
old.LifetimeManager is IDisposable disposable)
|
||||
{
|
||||
yield return previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private IPolicySet AddOrUpdateLegacy(Type type, string name, InternalRegistration registration)
|
||||
{
|
||||
var collisions = 0;
|
||||
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
using Unity.Policy;
|
||||
using Unity.Registration;
|
||||
using Unity.Resolution;
|
||||
using Unity.Storage;
|
||||
|
||||
namespace Unity
|
||||
{
|
||||
public partial class UnityContainer
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private Registry _registry;
|
||||
private Metadata _metadata;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region
|
||||
|
||||
private IPolicySet InitAndAdd(ref NamedType key, InternalRegistration registration)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (Register == InitAndAdd)
|
||||
{
|
||||
_registry = new Registry();
|
||||
_metadata = new Metadata();
|
||||
|
||||
Register = AddOrReplace;
|
||||
}
|
||||
}
|
||||
|
||||
return Register(ref key, registration);
|
||||
}
|
||||
|
||||
private IPolicySet AddOrReplace(ref NamedType key, InternalRegistration registration)
|
||||
{
|
||||
var hashCode = key.GetHashCode();
|
||||
var targetBucket = hashCode % _registry.Buckets.Length;
|
||||
var collisions = 0;
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
for (var i = _registry.Buckets[targetBucket]; i >= 0; i = _registry.Entries[i].Next)
|
||||
{
|
||||
ref var candidate = ref _registry.Entries[i];
|
||||
if (candidate.HashCode != hashCode ||
|
||||
candidate.Key.Type != key.Type)
|
||||
{
|
||||
collisions++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var existing = candidate.Reference;
|
||||
|
||||
candidate.Reference = registration;
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
if (_registry.RequireToGrow || ListToHashCutPoint < collisions)
|
||||
{
|
||||
_registry = new Registry(_registry);
|
||||
targetBucket = hashCode % _registry.Buckets.Length;
|
||||
}
|
||||
|
||||
ref var entry = ref _registry.Entries[_registry.Count];
|
||||
entry.HashCode = hashCode;
|
||||
entry.Next = _registry.Buckets[targetBucket];
|
||||
entry.Key = key;
|
||||
entry.Reference = registration;
|
||||
var position = _registry.Count++;
|
||||
_registry.Buckets[targetBucket] = position;
|
||||
_metadata.Add(key.Type, position);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -26,48 +26,6 @@ namespace Unity
|
|||
[SecuritySafeCritical]
|
||||
public partial class UnityContainer
|
||||
{
|
||||
#region Dynamic Registrations
|
||||
|
||||
private IPolicySet GetDynamicRegistration(Type type, string name)
|
||||
{
|
||||
var registration = _get(type, name);
|
||||
if (null != registration) return registration;
|
||||
|
||||
var info = type.GetTypeInfo();
|
||||
return !info.IsGenericType
|
||||
? _root.GetOrAdd(type, name)
|
||||
: GetOrAddGeneric(type, name, info.GetGenericTypeDefinition());
|
||||
}
|
||||
|
||||
private IPolicySet CreateRegistration(Type type, string name)
|
||||
{
|
||||
|
||||
var registration = new InternalRegistration(type, name);
|
||||
|
||||
if (type.GetTypeInfo().IsGenericType)
|
||||
{
|
||||
var factory = (InternalRegistration)_get(type.GetGenericTypeDefinition(), name);
|
||||
if (null != factory)
|
||||
{
|
||||
registration.InjectionMembers = factory.InjectionMembers;
|
||||
registration.Map = factory.Map;
|
||||
}
|
||||
}
|
||||
|
||||
registration.BuildChain = GetBuilders(type, registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
private IPolicySet CreateRegistration(Type type, Type policyInterface, object policy)
|
||||
{
|
||||
var registration = new InternalRegistration(policyInterface, policy);
|
||||
registration.BuildChain = GetBuilders(type, registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resolving Collections
|
||||
|
||||
internal static object ResolveEnumerable<TElement>(ref BuilderContext context)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Security;
|
||||
|
||||
namespace Unity.Utility
|
||||
{
|
||||
[SecuritySafeCritical]
|
||||
internal static class HashHelpers
|
||||
{
|
||||
// Table of prime numbers to use as hash table sizes.
|
||||
|
@ -74,5 +76,24 @@ namespace Unity.Utility
|
|||
|
||||
// This is the maximum prime smaller than Array.MaxArrayLength
|
||||
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
|
||||
|
||||
public static void FillArray(int[] array, int value)
|
||||
{
|
||||
#if !NET40
|
||||
unsafe
|
||||
{
|
||||
fixed (int* bucketsPtr = array)
|
||||
{
|
||||
int* ptr = bucketsPtr;
|
||||
var end = bucketsPtr + array.Length;
|
||||
while (ptr < end) *ptr++ = value;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for(int i = 0; i < array.Length; i++)
|
||||
array[i] = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\src\package.snk</AssemblyOriginatorKeyFile>
|
||||
<DelaySign>false</DelaySign>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\SpecificationTests\diagnostic\Unity.Specification.Diagnostic.csproj" />
|
||||
<ProjectReference Include="..\..\src\Unity.Container.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,32 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Unity;
|
||||
|
||||
namespace Registration
|
||||
{
|
||||
[TestClass]
|
||||
public class Type : Unity.Specification.Async.Registration.Types.SpecificationTests
|
||||
{
|
||||
public override IUnityContainerAsync GetContainer()
|
||||
{
|
||||
return new UnityContainer();
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class Factory : Unity.Specification.Async.Registration.Factory.SpecificationTests
|
||||
{
|
||||
public override IUnityContainerAsync GetContainer()
|
||||
{
|
||||
return new UnityContainer();
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class Instance : Unity.Specification.Async.Registration.Instance.SpecificationTests
|
||||
{
|
||||
public override IUnityContainerAsync GetContainer()
|
||||
{
|
||||
return new UnityContainer();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\src\package.snk</AssemblyOriginatorKeyFile>
|
||||
<DelaySign>false</DelaySign>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\SpecificationTestsAsync\src\Unity.Specification.Async.csproj" />
|
||||
<ProjectReference Include="..\..\src\Unity.Container.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче