.NETCORE 容器源码讲解
public interface IAService
{
void Hello();
}
public class AService : IAService , IDisposable
{
public AService(IBService bService)
{
}
public void Hello()
{
Console.WriteLine("Hello AService");
}
public void Dispose()
{
Console.WriteLine("AService Dispose Invoke");
}
}
public interface IBService
{
}
public class BService : IBService
{
public BService()
{
}
}
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IAService,AService>();
serviceCollection.AddScoped<IBService,BService>();
var options = new ServiceProviderOptions() { ValidateScopes = true, ValidateOnBuild = true };
using var rootServiceProvider = serviceCollection.BuildServiceProvider(options);
using var scope = rootServiceProvider.CreateScope();
var childServiceProvider = scope.ServiceProvider;
var aService = childServiceProvider.GetRequiredService<IAService>();
aService.Hello();
public interface IServiceCollection : IList<ServiceDescriptor>
{
}
public class ServiceDescriptor
{
public ServiceLifetime Lifetime { get; }
public Type ServiceType { get; }
public Type? ImplementationType { get; }
public object? ImplementationInstance { get; }
public Func<IServiceProvider, object>? ImplementationFactory { get; }
}
public class ServiceCollection :
IServiceCollection,
IList<ServiceDescriptor>,
ICollection<ServiceDescriptor>,
IEnumerable<ServiceDescriptor>,
IEnumerable
{
private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>();
public int Count => this._descriptors.Count;
public bool IsReadOnly => false;
public ServiceDescriptor this[int index]
{
get => this._descriptors[index];
set => this._descriptors[index] = value;
}
public void Clear() => this._descriptors.Clear();
public bool Contains(ServiceDescriptor item) => this._descriptors.Contains(item);
public void CopyTo(ServiceDescriptor[] array, int arrayIndex) => this._descriptors.CopyTo(array, arrayIndex);
public bool Remove(ServiceDescriptor item) => this._descriptors.Remove(item);
public IEnumerator<ServiceDescriptor> GetEnumerator() => (IEnumerator<ServiceDescriptor>) this._descriptors.GetEnumerator();
void ICollection<ServiceDescriptor>.Add(ServiceDescriptor item) => this._descriptors.Add(item);
IEnumerator IEnumerable.GetEnumerator() => (IEnumerator) this.GetEnumerator();
public int IndexOf(ServiceDescriptor item) => this._descriptors.IndexOf(item);
public void Insert(int index, ServiceDescriptor item) => this._descriptors.Insert(index, item);
public void RemoveAt(int index) => this._descriptors.RemoveAt(index);
}
public static IServiceCollection AddScoped<TService,TImplementation>(
this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
return services.AddScoped(typeof (TService), typeof (TImplementation));
}
public static IServiceCollection AddScoped(
this IServiceCollection services,
Type serviceType,
Type implementationType)
{
return ServiceCollectionServiceExtensions.Add(services, serviceType, implementationType, ServiceLifetime.Scoped);
}
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType,
ServiceLifetime lifetime)
{
ServiceDescriptor serviceDescriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(serviceDescriptor);
return collection;
}
public static ServiceProvider BuildServiceProvider(
this IServiceCollection services,
ServiceProviderOptions options)
{
if (services == null)
throw new ArgumentNullException(nameof (services));
return options != null ? new ServiceProvider((ICollection<ServiceDescriptor>) services, options) : throw new ArgumentNullException(nameof (options));
}
internal ServiceProvider(
ICollection<ServiceDescriptor> serviceDescriptors,
ServiceProviderOptions options)
{
this.Root = new ServiceProviderEngineScope(this, true);
this._engine = this.GetEngine();
this._createServiceAccessor = this.CreateServiceAccessor;
this._realizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
this.CallSiteFactory = new CallSiteFactory(serviceDescriptors);
this.CallSiteFactory.Add(typeof (IServiceProvider), (ServiceCallSite) new ServiceProviderCallSite());
this.CallSiteFactory.Add(typeof (IServiceScopeFactory), (ServiceCallSite) new ConstantCallSite(typeof (IServiceScopeFactory), (object) this.Root));
this.CallSiteFactory.Add(typeof (IServiceProviderIsService), (ServiceCallSite) new ConstantCallSite(typeof (IServiceProviderIsService), (object) this.CallSiteFactory));
}
public static IServiceScope CreateScope(this IServiceProvider provider)
{
return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
public IServiceScope CreateScope() => RootProvider.CreateScope();
internal IServiceScope CreateScope()
{
if (_disposed) ThrowHelper.ThrowObjectDisposedException();
return new ServiceProviderEngineScope(this, isRootScope: false);
}
internal sealed class ServiceProviderEngineScope :
IServiceScope,
IDisposable,
IServiceProvider,
IAsyncDisposable,
IServiceScopeFactory
{
private bool _disposed;
private List<object> _disposables;
internal IList<object> Disposables => (IList<object>) this._disposables ?? (IList<object>) Array.Empty<object>();
public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope);
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; }
internal object Sync => (object) this.ResolvedServices;
public bool IsRootScope { get; }
internal ServiceProvider RootProvider { get; }
public object GetService(Type serviceType)
{
if (this._disposed) ThrowHelper.ThrowObjectDisposedException();
return this.RootProvider.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => (IServiceProvider) this;
public IServiceScope CreateScope() => this.RootProvider.CreateScope();
public void Dispose()
{
List<object> objectList = this.BeginDispose();
if (objectList == null) return;
for (int index = objectList.Count - 1; index >= 0; --index) {disposable.Dispose();}
}
internal object CaptureDisposable(object service)
{
if (ReferenceEquals(this, service) || !(service is IDisposable || service is IAsyncDisposable)) return service;
lock (Sync){
_disposables ??= new List<object>();
_disposables.Add(service);
}
return service;
}
}
public object GetService(Type serviceType) => this.GetService(serviceType, this.Root);
internal object GetService(
Type serviceType,
ServiceProviderEngineScope serviceProviderEngineScope)
{
if (_disposed) ThrowHelper.ThrowObjectDisposedException();
Func<ServiceProviderEngineScope, object> realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
OnResolve(serviceType, serviceProviderEngineScope);
var result = realizedService.Invoke(serviceProviderEngineScope);
return result;
}
private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
OnCreate(callSite);
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
object value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
return scope => value;
}
return _engine.RealizeService(callSite);
}
return _ => null;
}
internal abstract class ServiceCallSite
{
public abstract Type ServiceType { get; }
public abstract Type ImplementationType { get; }
public abstract CallSiteKind Kind { get; }
public ResultCache Cache { get; }
public object Value { get; set; }
}
internal sealed class CallSiteFactory : IServiceProviderIsService{
public void Add(Type type, ServiceCallSite serviceCallSite)
{
_callSiteCache[new ServiceCacheKey(type, DefaultSlot)] = serviceCallSite;
}
public CallSiteFactory(ICollection<ServiceDescriptor> descriptors)
{
_stackGuard = new StackGuard();
_descriptors = new ServiceDescriptor[descriptors.Count];
descriptors.CopyTo(_descriptors, 0);
Populate();
}
private void Populate()
{
foreach (ServiceDescriptor descriptor in _descriptors)
{
Type serviceType = descriptor.ServiceType;
Type cacheKey = serviceType;
_descriptorLookup.TryGetValue(cacheKey, out ServiceDescriptorCacheItem cacheItem);
_descriptorLookup[cacheKey] = cacheItem.Add(descriptor);
}
}
internal ServiceCallSite GetCallSite(Type serviceType, CallSiteChain callSiteChain) =>
_callSiteCache.TryGetValue(new ServiceCacheKey(serviceType, DefaultSlot), out ServiceCallSite site) ? site :
CreateCallSite(serviceType, callSiteChain);
private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
{
var callsiteLock = _callSiteLocks.GetOrAdd(serviceType, static _ => new object());
lock (callsiteLock)
{
callSiteChain.CheckCircularDependency(serviceType);
ServiceCallSite callSite =
TryCreateExact(serviceType, callSiteChain) ??
TryCreateOpenGeneric(serviceType, callSiteChain) ??
TryCreateEnumerable(serviceType, callSiteChain);
return callSite;
}
}
private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
{
if (_descriptorLookup.TryGetValue(serviceType, out ServiceDescriptorCacheItem descriptor))
{
return TryCreateExact(descriptor.Last, serviceType, callSiteChain, DefaultSlot);
}
return null;
}
private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)
{
if (serviceType == descriptor.ServiceType)
{
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot);
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite))
return serviceCallSite;
ServiceCallSite callSite;
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
if (descriptor.ImplementationInstance != null)
{
callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);
}
else if (descriptor.ImplementationFactory != null)
{
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
}
else if (descriptor.ImplementationType != null)
{
callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);
}
else
{
throw new InvalidOperationException(SR.InvalidServiceDescriptor);
}
return _callSiteCache[callSiteKey] = callSite;
}
return null;
}
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>
{
public static CallSiteRuntimeResolver Instance { get; } = new();
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
if (scope.IsRootScope && callSite.Value is object cached)
{
return cached;
}
return VisitCallSite(callSite, new RuntimeResolverContext
{
Scope = scope
});
}
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
switch (callSite.Cache.Location)
{
case CallSiteResultCacheLocation.Root:
return VisitRootCache(callSite, argument);
case CallSiteResultCacheLocation.Scope:
return VisitScopeCache(callSite, argument);
case CallSiteResultCacheLocation.Dispose:
return VisitDisposeCache(callSite, argument);
case CallSiteResultCacheLocation.None:
return VisitNoCache(callSite, argument);
default:
throw new ArgumentOutOfRangeException();
}
}
protected override object VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
{
if (callSite.Value is object value) return value;
ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
lock (callSite)
{
if (callSite.Value is object resolved) return resolved;
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | RuntimeResolverLock.Root
});
serviceProviderEngine.CaptureDisposable(resolved);
callSite.Value = resolved;
return resolved;
}
}
protected override object VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
{
return context.Scope.IsRootScope ?
VisitRootCache(callSite, context) :
VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}
protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
{
return context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
}
、
private object VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
{
bool lockTaken = false;
object sync = serviceProviderEngine.Sync;
Dictionary<ServiceCacheKey, object> resolvedServices = serviceProviderEngine.ResolvedServices;
if ((context.AcquiredLocks & lockType) == 0)
{
Monitor.Enter(sync, ref lockTaken);
}
try
{
if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved))
{
return resolved;
}
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
serviceProviderEngine.CaptureDisposable(resolved);
resolvedServices.Add(callSite.Cache.Key, resolved);
return resolved;
}
finally
{
}
}
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
switch (callSite.Kind)
{
case CallSiteKind.Factory:
return VisitFactory((FactoryCallSite)callSite, argument);
case CallSiteKind.IEnumerable:
return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
case CallSiteKind.Constructor:
return VisitConstructor((ConstructorCallSite)callSite, argument);
case CallSiteKind.Constant:
return VisitConstant((ConstantCallSite)callSite, argument);
case CallSiteKind.ServiceProvider:
return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
default:
throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
}
}
protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
{
object[] parameterValues;
if (constructorCallSite.ParameterCallSites.Length == 0)
{
parameterValues = Array.Empty<object>();
}
else
{
parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
for (int index = 0; index < parameterValues.Length; index++)
{
parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
}
}
return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameterValues, culture: null);
}
protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
{
return constantCallSite.DefaultValue;
}
protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)
{
return context.Scope;
}
protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
object value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
}
protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
{
return factoryCallSite.Factory(context.Scope);
}
}