[Add] VContainer

This commit is contained in:
2026-04-07 04:51:37 +07:00
parent 76562726ec
commit 4f9b878775
193 changed files with 8036 additions and 0 deletions
@@ -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;
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 24bcedcfe70849f4b609a3c695bee2da
timeCreated: 1637460174
@@ -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;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e5fee000f6274ce19a7ee65eb42604e7
timeCreated: 1637894705
@@ -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);
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67ec193044734d97aa59126a9cb83398
timeCreated: 1637461669
@@ -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;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4fcef74c11fc4018bbc88bc395ef8657
timeCreated: 1619863673
@@ -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);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a4fb0cd9294e424bb69b28711f95ccc0
timeCreated: 1619867067
@@ -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);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7f72f5485924ec19d7761e215e23a16
timeCreated: 1637903141
@@ -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();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 927f2cb4e816642cba170d66ffc1fcb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: