[Add] VContainer
This commit is contained in:
+131
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
struct RegistrationElement
|
||||
{
|
||||
public Registration Registration;
|
||||
public IObjectResolver RegisteredContainer;
|
||||
|
||||
public RegistrationElement(Registration registration, IObjectResolver registeredContainer)
|
||||
{
|
||||
Registration = registration;
|
||||
RegisteredContainer = registeredContainer;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CollectionInstanceProvider : IInstanceProvider, IEnumerable<Registration>
|
||||
{
|
||||
public static bool Match(Type openGenericType) => openGenericType == typeof(IEnumerable<>) ||
|
||||
openGenericType == typeof(IReadOnlyList<>);
|
||||
|
||||
public List<Registration>.Enumerator GetEnumerator() => registrations.GetEnumerator();
|
||||
IEnumerator<Registration> IEnumerable<Registration>.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public Type ImplementationType { get; }
|
||||
public IReadOnlyList<Type> InterfaceTypes => interfaceTypes;
|
||||
public Lifetime Lifetime => Lifetime.Transient; // Collection reference is transient. So its members can have each lifetimes.
|
||||
|
||||
public Type ElementType { get; }
|
||||
|
||||
readonly List<Type> interfaceTypes;
|
||||
readonly List<Registration> registrations = new List<Registration>();
|
||||
|
||||
public CollectionInstanceProvider(Type elementType)
|
||||
{
|
||||
ElementType = elementType;
|
||||
ImplementationType = elementType.MakeArrayType();
|
||||
interfaceTypes = new List<Type>
|
||||
{
|
||||
RuntimeTypeCache.EnumerableTypeOf(elementType),
|
||||
RuntimeTypeCache.ReadOnlyListTypeOf(elementType),
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var contractTypes = InterfaceTypes != null ? string.Join(", ", InterfaceTypes) : "";
|
||||
return $"CollectionRegistration {ImplementationType} ContractTypes=[{contractTypes}] {Lifetime}";
|
||||
}
|
||||
|
||||
public void Add(Registration registration)
|
||||
{
|
||||
foreach (var x in registrations)
|
||||
{
|
||||
if (x.Lifetime == Lifetime.Singleton && x.ImplementationType == registration.ImplementationType && x.Key == registration.Key)
|
||||
{
|
||||
throw new VContainerException(registration.ImplementationType, $"Conflict implementation type : {registration}");
|
||||
}
|
||||
}
|
||||
registrations.Add(registration);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
if (resolver is IScopedObjectResolver scope)
|
||||
{
|
||||
using (ListPool<RegistrationElement>.Get(out var entirelyRegistrations))
|
||||
{
|
||||
CollectFromParentScopes(scope, entirelyRegistrations);
|
||||
return SpawnInstance(resolver, entirelyRegistrations);
|
||||
}
|
||||
}
|
||||
|
||||
var array = Array.CreateInstance(ElementType, registrations.Count);
|
||||
for (var i = 0; i < registrations.Count; i++)
|
||||
{
|
||||
array.SetValue(resolver.Resolve(registrations[i]), i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal object SpawnInstance(IObjectResolver currentScope, IReadOnlyList<RegistrationElement> entirelyRegistrations)
|
||||
{
|
||||
var array = Array.CreateInstance(ElementType, entirelyRegistrations.Count);
|
||||
for (var i = 0; i < entirelyRegistrations.Count; i++)
|
||||
{
|
||||
var x = entirelyRegistrations[i];
|
||||
var resolver = x.Registration.Lifetime == Lifetime.Singleton
|
||||
? x.RegisteredContainer
|
||||
: currentScope;
|
||||
array.SetValue(resolver.Resolve(x.Registration), i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal void CollectFromParentScopes(
|
||||
IScopedObjectResolver scope,
|
||||
List<RegistrationElement> registrationsBuffer,
|
||||
bool localScopeOnly = false)
|
||||
{
|
||||
foreach (var registration in registrations)
|
||||
{
|
||||
registrationsBuffer.Add(new RegistrationElement(registration, scope));
|
||||
}
|
||||
|
||||
var finderType = InterfaceTypes[0];
|
||||
scope = scope.Parent;
|
||||
|
||||
while (scope != null)
|
||||
{
|
||||
if (scope.TryGetRegistration(finderType, out var registration) &&
|
||||
registration.Provider is CollectionInstanceProvider parentCollection)
|
||||
{
|
||||
foreach (var x in parentCollection.registrations)
|
||||
{
|
||||
if (!localScopeOnly || x.Lifetime != Lifetime.Singleton)
|
||||
{
|
||||
registrationsBuffer.Add(new RegistrationElement(x, scope));
|
||||
}
|
||||
}
|
||||
}
|
||||
scope = scope.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24bcedcfe70849f4b609a3c695bee2da
|
||||
timeCreated: 1637460174
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
sealed class ContainerInstanceProvider : IInstanceProvider
|
||||
{
|
||||
public static readonly ContainerInstanceProvider Default = new ContainerInstanceProvider();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver) => resolver;
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5fee000f6274ce19a7ee65eb42604e7
|
||||
timeCreated: 1637894705
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
sealed class ContainerLocalInstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly Type wrappedType;
|
||||
readonly Registration valueRegistration;
|
||||
|
||||
public ContainerLocalInstanceProvider(Type wrappedType, Registration valueRegistration)
|
||||
{
|
||||
this.wrappedType = wrappedType;
|
||||
this.valueRegistration = valueRegistration;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
object value;
|
||||
|
||||
if (resolver is ScopedContainer scope &&
|
||||
valueRegistration.Provider is CollectionInstanceProvider collectionProvider)
|
||||
{
|
||||
using (ListPool<RegistrationElement>.Get(out var entirelyRegistrations))
|
||||
{
|
||||
collectionProvider.CollectFromParentScopes(scope, entirelyRegistrations, localScopeOnly: true);
|
||||
value = collectionProvider.SpawnInstance(scope, entirelyRegistrations);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = resolver.Resolve(valueRegistration);
|
||||
}
|
||||
var parameterValues = CappedArrayPool<object>.Shared8Limit.Rent(1);
|
||||
try
|
||||
{
|
||||
parameterValues[0] = value;
|
||||
return Activator.CreateInstance(wrappedType, parameterValues);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CappedArrayPool<object>.Shared8Limit.Return(parameterValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67ec193044734d97aa59126a9cb83398
|
||||
timeCreated: 1637461669
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
sealed class ExistingInstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly object implementationInstance;
|
||||
|
||||
public ExistingInstanceProvider(object implementationInstance)
|
||||
{
|
||||
this.implementationInstance = implementationInstance;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver) => implementationInstance;
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fcef74c11fc4018bbc88bc395ef8657
|
||||
timeCreated: 1619863673
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
sealed class FuncInstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly Func<IObjectResolver, object> implementationProvider;
|
||||
|
||||
public FuncInstanceProvider(Func<IObjectResolver, object> implementationProvider)
|
||||
{
|
||||
this.implementationProvider = implementationProvider;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver) => implementationProvider(resolver);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4fb0cd9294e424bb69b28711f95ccc0
|
||||
timeCreated: 1619867067
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
sealed class InstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
|
||||
public InstanceProvider(
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters = null)
|
||||
{
|
||||
this.injector = injector;
|
||||
this.customParameters = customParameters;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
=> injector.CreateInstance(resolver, customParameters);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7f72f5485924ec19d7761e215e23a16
|
||||
timeCreated: 1637903141
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace VContainer.Internal
|
||||
{
|
||||
public class OpenGenericInstanceProvider : IInstanceProvider
|
||||
{
|
||||
class TypeParametersKey
|
||||
{
|
||||
public readonly Type[] TypeParameters;
|
||||
public readonly object Key;
|
||||
|
||||
public TypeParametersKey(Type[] typeParameters, object key)
|
||||
{
|
||||
TypeParameters = typeParameters;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is TypeParametersKey other)
|
||||
{
|
||||
if (Key != other.Key)
|
||||
return false;
|
||||
|
||||
if (TypeParameters.Length != other.TypeParameters.Length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < TypeParameters.Length; i++)
|
||||
{
|
||||
if (TypeParameters[i] != other.TypeParameters[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = 5381;
|
||||
foreach (var typeParameter in TypeParameters)
|
||||
{
|
||||
hash = ((hash << 5) + hash) ^ typeParameter.GetHashCode();
|
||||
}
|
||||
hash = ((hash << 5) + hash) ^ (Key?.GetHashCode() ?? 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
readonly Lifetime lifetime;
|
||||
readonly Type implementationType;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
|
||||
readonly ConcurrentDictionary<TypeParametersKey, Registration> constructedRegistrations = new ConcurrentDictionary<TypeParametersKey, Registration>();
|
||||
readonly Func<TypeParametersKey, Registration> createRegistrationFunc;
|
||||
|
||||
public OpenGenericInstanceProvider(Type implementationType, Lifetime lifetime, List<IInjectParameter> injectParameters)
|
||||
{
|
||||
this.implementationType = implementationType;
|
||||
this.lifetime = lifetime;
|
||||
customParameters = injectParameters;
|
||||
createRegistrationFunc = CreateRegistration;
|
||||
}
|
||||
|
||||
public Registration GetClosedRegistration(Type closedInterfaceType, Type[] typeParameters, object key = null)
|
||||
{
|
||||
var typeParametersKey = new TypeParametersKey(typeParameters, key);
|
||||
return constructedRegistrations.GetOrAdd(typeParametersKey, createRegistrationFunc);
|
||||
}
|
||||
|
||||
Registration CreateRegistration(TypeParametersKey key)
|
||||
{
|
||||
var newType = implementationType.MakeGenericType(key.TypeParameters);
|
||||
var injector = InjectorCache.GetOrBuild(newType);
|
||||
var spawner = new InstanceProvider(injector, customParameters);
|
||||
return new Registration(newType, lifetime, new List<Type>(1) { newType }, spawner, key.Key);
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 927f2cb4e816642cba170d66ffc1fcb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user