This commit is contained in:
Eugene Sadovoi 2019-04-08 23:17:56 -04:00
Родитель 105c9a6cfe
Коммит e0ea6e2cd5
9 изменённых файлов: 219 добавлений и 159 удалений

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

@ -64,7 +64,9 @@ namespace Unity.Builder
}
}
return Resolve(type, name, (InternalRegistration)((UnityContainer)Container).GetRegistration(type, name));
NamedType key = new NamedType { Name = name, Type = type };
return Resolve(type, name, (InternalRegistration)((UnityContainer)Container).GetRegistration(ref key));
}
#endregion

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

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Unity.Utility;
namespace Unity.Storage
@ -12,6 +14,7 @@ namespace Unity.Storage
private int[] Buckets;
private Entry[] Entries;
private int Count;
public static readonly int[] Empty = new int[0];
#endregion
@ -76,14 +79,33 @@ namespace Unity.Storage
// 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 };
entry.HashCode = hashCode;
Buckets[targetBucket] = Count++;
}
// TODO: Performance
public IEnumerable<int> Get(Type key)
{
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;
var count = candidate.Count;
var data = candidate.Data;
return data.Take(count);
}
return Empty;
}
#endregion

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

@ -1,5 +1,5 @@
using System;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
using Unity.Utility;
@ -59,7 +59,7 @@ namespace Unity.Storage
public int HashCode;
public NamedType Key;
public int Next;
public IPolicySet Reference;
public InternalRegistration Registration;
}
#endregion

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

@ -44,20 +44,23 @@ namespace Unity
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
var registration = new ContainerRegistration(_validators, typeTo, (LifetimeManager)lifetimeManager, injectionMembers);
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable disposableManager)
container.LifetimeContainer.Add(disposableManager);
// Add or replace existing
var previous = container.RegisterLegacy(registeredType, name, registration);
if (previous is ContainerRegistration old &&
old.LifetimeManager is IDisposable disposable)
NamedType key = new NamedType { Name = name, Type = registeredType };
var previous = container.Register(ref key, registration);
// Allow reference adjustment and disposal
if (null != previous && 0 == previous.Release()
&& previous.LifetimeManager is IDisposable disposable)
{
// Dispose replaced lifetime manager
container.LifetimeContainer.Remove(disposable);
disposable.Dispose();
}
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable disposableManager)
container.LifetimeContainer.Add(disposableManager);
// Add Injection Members
if (null != injectionMembers && injectionMembers.Length > 0)
{
@ -109,12 +112,12 @@ namespace Unity
IUnityContainer IUnityContainer.RegisterInstance(Type type, string name, object instance, IInstanceLifetimeManager lifetimeManager)
{
var mappedToType = instance?.GetType();
var typeFrom = type ?? mappedToType;
var registeredType = type ?? mappedToType;
try
{
// Validate input
if (null == typeFrom) throw new InvalidOperationException($"At least one of Type arguments '{nameof(type)}' or '{nameof(instance)}' must be not 'null'");
if (null == registeredType) throw new InvalidOperationException($"At least one of Type arguments '{nameof(type)}' or '{nameof(instance)}' must be not 'null'");
if (null == lifetimeManager) lifetimeManager = new ContainerControlledLifetimeManager();
if (((LifetimeManager)lifetimeManager).InUse) throw new InvalidOperationException(LifetimeManagerInUse);
@ -124,26 +127,29 @@ namespace Unity
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
var registration = new ContainerRegistration(null, mappedToType, ((LifetimeManager)lifetimeManager));
// Add or replace existing
var previous = container.RegisterLegacy(typeFrom, name, registration);
if (previous is ContainerRegistration old &&
old.LifetimeManager is IDisposable disposable)
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable manager)
container.LifetimeContainer.Add(manager);
// Register type
NamedType key = new NamedType { Name = name, Type = registeredType };
var previous = container.Register(ref key, registration);
// Allow reference adjustment and disposal
if (null != previous && 0 == previous.Release()
&& previous.LifetimeManager is IDisposable disposable)
{
// Dispose replaced lifetime manager
container.LifetimeContainer.Remove(disposable);
disposable.Dispose();
}
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable manager)
container.LifetimeContainer.Add(manager);
// Check what strategies to run
registration.BuildChain = _strategiesChain.ToArray()
.Where(strategy => strategy.RequiredToResolveInstance(this, registration))
.ToArray();
.Where(strategy => strategy.RequiredToResolveInstance(this, registration))
.ToArray();
// Raise event
container.RegisteringInstance?.Invoke(this, new RegisterInstanceEventArgs(typeFrom, instance,
container.RegisteringInstance?.Invoke(this, new RegisterInstanceEventArgs(registeredType, instance,
name, ((LifetimeManager)lifetimeManager)));
}
catch (Exception ex)
@ -153,7 +159,7 @@ namespace Unity
if (null != name) parts.Add($" '{name}'");
if (null != lifetimeManager && !(lifetimeManager is TransientLifetimeManager)) parts.Add(lifetimeManager.ToString());
var message = $"Error in RegisterInstance<{typeFrom?.Name}>({string.Join(", ", parts)})";
var message = $"Error in RegisterInstance<{registeredType?.Name}>({string.Join(", ", parts)})";
throw new InvalidOperationException(message, ex);
}
@ -183,9 +189,12 @@ namespace Unity
var registration = new ContainerRegistration(_validators, type, ((LifetimeManager)lifetimeManager), injectionMembers);
// Add or replace existing
var previous = container.RegisterLegacy(type, name, registration);
if (previous is ContainerRegistration old &&
old.LifetimeManager is IDisposable disposable)
NamedType key = new NamedType { Name = name, Type = type };
var previous = container.Register(ref key, registration);
// Allow reference adjustment and disposal
if (null != previous && 0 == previous.Release()
&& previous.LifetimeManager is IDisposable disposable)
{
// Dispose replaced lifetime manager
container.LifetimeContainer.Remove(disposable);
@ -234,7 +243,8 @@ namespace Unity
if (null == type) throw new ArgumentNullException(nameof(type));
name = string.IsNullOrEmpty(name) ? null : name;
var registration = (InternalRegistration)GetRegistration(type, name);
NamedType key = new NamedType { Name = name, Type = type };
var registration = (InternalRegistration)GetRegistration(ref key);
var context = new BuilderContext
{
List = new PolicyList(),
@ -266,7 +276,8 @@ namespace Unity
// Validate if they are assignable
if (null != existing && null != TypeValidator) TypeValidator(type, existing.GetType());
var registration = (InternalRegistration)GetRegistration(type, name);
NamedType key = new NamedType { Name = name, Type = type };
var registration = (InternalRegistration)GetRegistration(ref key);
var context = new BuilderContext
{
List = new PolicyList(),

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

@ -100,6 +100,9 @@ namespace Unity
var container = lifetimeManager is SingletonLifetimeManager ? _root : this;
var registration = new ContainerRegistration(mappedToType, (LifetimeManager)lifetimeManager);
// If Disposable add to container's lifetime
if (lifetimeManager is IDisposable manager) container.LifetimeContainer.Add(manager);
// Register interfaces
var replaced = container.AddOrReplaceRegistrations(interfaces, name, registration)
.ToArray();

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

@ -54,11 +54,6 @@ namespace Unity
private event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated;
// Methods
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal Func<Type, string, IPolicySet> GetRegistration;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal Func<Type, string, InternalRegistration, IPolicySet> RegisterLegacy;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal GetPolicyDelegate GetPolicy;
@ -107,7 +102,6 @@ namespace Unity
IsTypeExplicitlyRegistered = _parent.IsTypeExplicitlyRegistered;
GetRegistration = _parent.GetRegistration;
RegisterLegacy = CreateAndSetOrUpdate;
GetPolicy = parent.GetPolicy;
SetPolicy = CreateAndSetPolicy;
ClearPolicy = delegate { };
@ -256,13 +250,10 @@ namespace Unity
_registrations = new Registrations(ContainerInitialCapacity);
Set(null, null, Defaults);
RegisterLegacy = AddOrUpdateLegacy;
GetPolicy = Get;
SetPolicy = Set;
ClearPolicy = Clear;
GetRegistration = GetDynamicRegistration;
_get = (type, name) => Get(type, name) ?? _parent._get(type, name);
_getGenericRegistration = GetOrAddGeneric;
IsTypeExplicitlyRegistered = IsTypeTypeExplicitlyRegisteredLocally;

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

@ -41,8 +41,6 @@ namespace Unity
_isExplicitlyRegistered = IsExplicitlyRegisteredLocally;
IsTypeExplicitlyRegistered = IsTypeTypeExplicitlyRegisteredLocally;
GetRegistration = GetOrAdd;
RegisterLegacy = AddOrUpdateLegacy;
GetPolicy = Get;
SetPolicy = Set;
ClearPolicy = Clear;
@ -81,7 +79,6 @@ 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

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

@ -23,7 +23,19 @@ namespace Unity
#region Delegates
private delegate IPolicySet RegisterDelegate(ref NamedType key, InternalRegistration registration);
private delegate InternalRegistration RegisterDelegate(ref NamedType key, InternalRegistration registration);
internal delegate InternalRegistration GetRegistrationDelegate(ref NamedType key);
#endregion
#region Registration Methods
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private RegisterDelegate Register;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal GetRegistrationDelegate GetRegistration;
#endregion
@ -31,8 +43,6 @@ namespace Unity
#region Registration Fields
// Register single type
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private RegisterDelegate Register;
internal IPolicySet Defaults;
private readonly object _syncRoot = new object();
@ -191,40 +201,15 @@ namespace Unity
var seed = null != container._parent ? GetRegistrations(container._parent)
: new RegistrationSet();
if (null == container._registrations) return seed;
if (null == container._registry) return seed;
var length = container._registrations.Count;
var entries = container._registrations.Entries;
var registry = container._registry;
for (var i = null == container._parent ? GetStartIndex() : 0; i < length; i++)
for (var i = null == container._parent ? GetStartIndex() : 0; i < registry.Count; i++)
{
ref var entry = ref entries[i];
var registry = entry.Value;
switch (registry)
{
case LinkedRegistry linkedRegistry:
for (var node = (LinkedNode<string, IPolicySet>)linkedRegistry; null != node; node = node.Next)
{
if (node.Value is ContainerRegistration containerRegistration)
seed.Add(entry.Key, node.Key, containerRegistration);
}
break;
case HashRegistry hashRegistry:
var count = hashRegistry.Count;
var nodes = hashRegistry.Entries;
for (var j = 0; j < count; j++)
{
ref var refNode = ref nodes[j];
if (refNode.Value is ContainerRegistration containerRegistration)
seed.Add(entry.Key, refNode.Key, containerRegistration);
}
break;
default:
throw new InvalidOperationException("Unknown type of registry");
}
ref var entry = ref registry.Entries[i];
if (entry.Registration is ContainerRegistration containerRegistration)
seed.Add(entry.Key.Type, entry.Key.Name, containerRegistration);
}
return seed;
@ -232,9 +217,9 @@ namespace Unity
int GetStartIndex()
{
int start = -1;
while (++start < length)
while (++start < registry.Count)
{
if (typeof(IUnityContainer) != container._registrations.Entries[start].Key)
if (typeof(IUnityContainer) != container._registry.Entries[start].Key.Type)
continue;
return start;
}
@ -248,36 +233,17 @@ namespace Unity
var seed = null != container._parent ? GetRegistrations(container._parent, types)
: new RegistrationSet();
if (null == container._registrations) return seed;
if (null == container._registry) return seed;
var registry = container._registry;
foreach (var type in types)
{
var registry = container.Get(type);
if (null == registry?.Values) continue;
switch (registry)
foreach (var i in container._metadata.Get(type))
{
case LinkedRegistry linkedRegistry:
for (var node = (LinkedNode<string, IPolicySet>)linkedRegistry; null != node; node = node.Next)
{
if (node.Value is ContainerRegistration containerRegistration)
seed.Add(type, node.Key, containerRegistration);
}
break;
case HashRegistry hashRegistry:
var count = hashRegistry.Count;
var nodes = hashRegistry.Entries;
for (var j = 0; j < count; j++)
{
ref var refNode = ref nodes[j];
if (refNode.Value is ContainerRegistration containerRegistration)
seed.Add(type, refNode.Key, containerRegistration);
}
break;
default:
throw new InvalidOperationException("Unknown type of registry");
ref var entry = ref registry.Entries[i];
if (entry.Registration is ContainerRegistration containerRegistration)
seed.Add(entry.Key.Type, entry.Key.Name, containerRegistration);
}
}
@ -291,34 +257,15 @@ namespace Unity
if (null == container._registrations) return seed;
var registry = container._registry;
foreach (var type in types)
{
var registry = container.Get(type);
if (null == registry?.Values) continue;
switch (registry)
foreach (var i in container._metadata.Get(type))
{
case LinkedRegistry linkedRegistry:
for (var node = (LinkedNode<string, IPolicySet>)linkedRegistry; null != node; node = node.Next)
{
if (node.Value is ContainerRegistration containerRegistration && !string.IsNullOrEmpty(node.Key))
seed.Add(type, node.Key, containerRegistration);
}
break;
case HashRegistry hashRegistry:
var count = hashRegistry.Count;
var nodes = hashRegistry.Entries;
for (var j = 0; j < count; j++)
{
ref var refNode = ref nodes[j];
if (refNode.Value is ContainerRegistration containerRegistration && !string.IsNullOrEmpty(refNode.Key))
seed.Add(type, refNode.Key, containerRegistration);
}
break;
default:
throw new InvalidOperationException("Unknown type of registry");
ref var entry = ref registry.Entries[i];
if (entry.Registration is ContainerRegistration containerRegistration && !string.IsNullOrEmpty(entry.Key.Name))
seed.Add(entry.Key.Type, entry.Key.Name, containerRegistration);
}
}
@ -365,8 +312,36 @@ namespace Unity
: GetOrAddGeneric(type, name, info.GetGenericTypeDefinition());
}
private InternalRegistration CreateRegistration(ref NamedType key)
{
// TODO: Verify constructor
var registration = new InternalRegistration(key.Type, key.Name);
if (key.Type.GetTypeInfo().IsGenericType)
{
var factory = (InternalRegistration)_get(key.Type.GetGenericTypeDefinition(), key.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(key.Type, registration);
return registration;
}
private IPolicySet CreateRegistration(Type type, string name)
{
// TODO: Verify constructor
var registration = new InternalRegistration(type, name);
if (type.GetTypeInfo().IsGenericType)
@ -405,8 +380,8 @@ namespace Unity
private IEnumerable<IPolicySet> AddOrReplaceRegistrations(IEnumerable<Type> interfaces, string name, ContainerRegistration registration)
{
NamedType key;
int count = 0;
int count = 0;
key.Name = name;
if (null != interfaces)
@ -418,16 +393,7 @@ namespace Unity
// 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;
}
if (null != previous) yield return previous;
count++;
}
@ -443,20 +409,16 @@ namespace Unity
// 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;
}
if (null != previous) yield return previous;
}
}
#endregion
#region Legacy
private IPolicySet AddOrUpdateLegacy(Type type, string name, InternalRegistration registration)
{
var collisions = 0;

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

@ -1,4 +1,4 @@
using Unity.Policy;
using System.Diagnostics;
using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
@ -7,6 +7,13 @@ namespace Unity
{
public partial class UnityContainer
{
#region Constants
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private const int CollisionsCutPoint = 5;
#endregion
#region Fields
private Registry _registry;
@ -15,9 +22,9 @@ namespace Unity
#endregion
#region
#region Registrations Manipulation
private IPolicySet InitAndAdd(ref NamedType key, InternalRegistration registration)
private InternalRegistration InitAndAdd(ref NamedType key, InternalRegistration registration)
{
lock (_syncRoot)
{
@ -27,15 +34,16 @@ namespace Unity
_metadata = new Metadata();
Register = AddOrReplace;
GetRegistration = GetOrAdd;
}
}
return Register(ref key, registration);
}
private IPolicySet AddOrReplace(ref NamedType key, InternalRegistration registration)
private InternalRegistration AddOrReplace(ref NamedType key, InternalRegistration registration)
{
var hashCode = key.GetHashCode();
var hashCode = key.GetHashCode() & 0x7FFFFFFF;
var targetBucket = hashCode % _registry.Buckets.Length;
var collisions = 0;
@ -51,24 +59,30 @@ namespace Unity
continue;
}
var existing = candidate.Reference;
// Replace registration
var existing = candidate.Registration;
candidate.Reference = registration;
candidate.Registration = registration;
candidate.Registration.AddRef();
return existing;
}
if (_registry.RequireToGrow || ListToHashCutPoint < collisions)
// Expand if required
if (_registry.RequireToGrow || CollisionsCutPoint < collisions)
{
_registry = new Registry(_registry);
targetBucket = hashCode % _registry.Buckets.Length;
}
// Add registration
ref var entry = ref _registry.Entries[_registry.Count];
entry.HashCode = hashCode;
entry.Next = _registry.Buckets[targetBucket];
entry.Key = key;
entry.Reference = registration;
entry.Registration = registration;
entry.Registration.AddRef();
var position = _registry.Count++;
_registry.Buckets[targetBucket] = position;
_metadata.Add(key.Type, position);
@ -77,6 +91,64 @@ namespace Unity
}
}
private InternalRegistration GetOrAdd(ref NamedType key)
{
var hashCode = key.GetHashCode() & 0x7FFFFFFF;
var targetBucket = hashCode % _registry.Buckets.Length;
var registry = _registry;
// Check for existing without squaring the lock first
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)
{
continue;
}
// Found a registration
return candidate.Registration;
}
// Nothing found so get the lock and add a new registration
// Do the double-check lock to verify it was not yet added
lock (_syncRoot)
{
var collisions = 0;
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;
}
return candidate.Registration;
}
if (_registry.RequireToGrow || CollisionsCutPoint < collisions)
{
_registry = new Registry(_registry);
targetBucket = hashCode % _registrations.Buckets.Length;
}
// Add registration
ref var entry = ref _registry.Entries[_registry.Count];
entry.HashCode = hashCode;
entry.Next = _registry.Buckets[targetBucket];
entry.Key = key;
entry.Registration = CreateRegistration(ref key);
entry.Registration.AddRef();
_registry.Buckets[targetBucket] = _registry.Count++;
return entry.Registration;
}
}
#endregion
}