网站的二维码怎么做,做淘宝一件代发的网站,江苏弘仁建设有限公司网站,营销课程动手造轮子#xff1a;实现一个简单的依赖注入(一)Intro在上一篇文章中主要介绍了一下要做的依赖注入的整体设计和大概编程体验#xff0c;这篇文章要开始写代码了#xff0c;开始实现自己的依赖注入框架。类图首先来温习一下上次提到的类图服务生命周期服务生命周期定义实现一个简单的依赖注入(一)Intro在上一篇文章中主要介绍了一下要做的依赖注入的整体设计和大概编程体验这篇文章要开始写代码了开始实现自己的依赖注入框架。类图首先来温习一下上次提到的类图服务生命周期服务生命周期定义public enum ServiceLifetime : sbyte
{ /// summary /// Specifies that a single instance of the service will be created. /// /summary Singleton 0, /// summary /// Specifies that a new instance of the service will be created for each scope. /// /summary Scoped 1, /// summary /// Specifies that a new instance of the service will be created every time it is requested. /// /summary Transient 2,
}服务定义服务注册定义public class ServiceDefinition
{ // 服务生命周期 public ServiceLifetime ServiceLifetime { get; } // 实现类型 public Type ImplementType { get; } // 服务类型 public Type ServiceType { get; } // 实现实例 public object ImplementationInstance { get; } // 实现工厂 public FuncIServiceProvider, object ImplementationFactory { get; } // 获取真实的实现类型 public Type GetImplementType() { if (ImplementationInstance ! null) return ImplementationInstance.GetType(); if (ImplementationFactory ! null) return ImplementationFactory.Method.DeclaringType; if (ImplementType ! null) return ImplementType; return ServiceType; } public ServiceDefinition(object instance, Type serviceType) { ImplementationInstance instance; ServiceType serviceType; ServiceLifetime ServiceLifetime.Singleton; } public ServiceDefinition(Type serviceType, ServiceLifetime serviceLifetime) : this(serviceType, serviceType, serviceLifetime) { } public ServiceDefinition(Type serviceType, Type implementType, ServiceLifetime serviceLifetime) { ServiceType serviceType; ImplementType implementType ?? serviceType; ServiceLifetime serviceLifetime; } public ServiceDefinition(Type serviceType, FuncIServiceProvider, object factory, ServiceLifetime serviceLifetime) { ServiceType serviceType; ImplementationFactory factory; ServiceLifetime serviceLifetime; }
}为了使用起来更方便添加了一些静态方法public static ServiceDefinition SingletonTService(FuncIServiceProvider, object factory)
{ return new ServiceDefinition(typeof(TService), factory, ServiceLifetime.Singleton);
}
public static ServiceDefinition ScopedTService(FuncIServiceProvider, object factory)
{ return new ServiceDefinition(typeof(TService), factory, ServiceLifetime.Scoped);
}
public static ServiceDefinition TransientTService(FuncIServiceProvider, object factory)
{ return new ServiceDefinition(typeof(TService), factory, ServiceLifetime.Transient);
}
public static ServiceDefinition SingletonTService()
{ return new ServiceDefinition(typeof(TService), ServiceLifetime.Singleton);
}
public static ServiceDefinition ScopedTService()
{ return new ServiceDefinition(typeof(TService), ServiceLifetime.Scoped);
}
public static ServiceDefinition TransientTService()
{ return new ServiceDefinition(typeof(TService), ServiceLifetime.Transient);
}
public static ServiceDefinition SingletonTService, TServiceImplement() where TServiceImplement : TService
{ return new ServiceDefinition(typeof(TService), typeof(TServiceImplement), ServiceLifetime.Singleton);
}
public static ServiceDefinition ScopedTService, TServiceImplement() where TServiceImplement : TService
{ return new ServiceDefinition(typeof(TService), typeof(TServiceImplement), ServiceLifetime.Scoped);
}
public static ServiceDefinition TransientTService, TServiceImplement() where TServiceImplement : TService
{ return new ServiceDefinition(typeof(TService), typeof(TServiceImplement), ServiceLifetime.Transient);
}ServiceContainerserviceContainer v1public class ServiceContainer : IServiceContainer
{ internal readonly ListServiceDefinition _services; private readonly ConcurrentDictionaryType, object _singletonInstances; private readonly ConcurrentDictionaryType, object _scopedInstances; private readonly Listobject _transientDisposables new Listobject(); private readonly bool _isRootScope; public ServiceContainer() { _isRootScope true; _singletonInstances new ConcurrentDictionaryType, object(); _services new ListServiceDefinition(); } internal ServiceContainer(ServiceContainer serviceContainer) { _isRootScope false; _singletonInstances serviceContainer._singletonInstances; _services serviceContainer._services; _scopedInstances new ConcurrentDictionaryType, object(); } public void Add(ServiceDefinition item) { _services.Add(item); } public IServiceContainer CreateScope() { return new ServiceContainer(this); } private bool _disposed; public void Dispose() { if (_disposed) { return; } if (_isRootScope) { lock (_singletonInstances) { if (_disposed) { return; } _disposed true; foreach (var instance in _singletonInstances.Values) { (instance as IDisposable)?.Dispose(); } foreach (var o in _transientDisposables) { (o as IDisposable)?.Dispose(); } } } else { lock (_scopedInstances) { if (_disposed) { return; } _disposed true; foreach (var instance in _scopedInstances.Values) { (instance as IDisposable)?.Dispose(); } foreach (var o in _transientDisposables) { (o as IDisposable)?.Dispose(); } } } } private object GetServiceInstance(Type serviceType, ServiceDefinition serviceDefinition) { if (serviceDefinition.ImplementationInstance ! null) return serviceDefinition.ImplementationInstance; if (serviceDefinition.ImplementationFactory ! null) return serviceDefinition.ImplementationFactory.Invoke(this); var implementType (serviceDefinition.ImplementType ?? serviceType); if (implementType.IsInterface || implementType.IsAbstract) { throw new InvalidOperationException($invalid service registered, serviceType: {serviceType.FullName}, implementType: {serviceDefinition.ImplementType}); } var ctorInfos implementType.GetConstructors(BindingFlags.Instance | BindingFlags.Public); if (ctorInfos.Length 0) { throw new InvalidOperationException($service {serviceType.FullName} does not have any public constructors); } ConstructorInfo ctor; if (ctorInfos.Length 1) { ctor ctorInfos[0]; } else { // try find best ctor ctor ctorInfos .OrderBy(_ _.GetParameters().Length) .First(); } var parameters ctor.GetParameters(); if (parameters.Length 0) { // TODO: cache New Func return Expression.LambdaFuncobject(Expression.New(ctor)).Compile().Invoke(); } else { var ctorParams new object[parameters.Length]; for (var index 0; index parameters.Length; index) { var parameter parameters[index]; var param GetService(parameter.ParameterType); if (param null parameter.HasDefaultValue) { param parameter.DefaultValue; } ctorParams[index] param; } return Expression.LambdaFuncobject(Expression.New(ctor, ctorParams.Select(Expression.Constant))).Compile().Invoke(); } } public object GetService(Type serviceType) { var serviceDefinition _services.LastOrDefault(_ _.ServiceType serviceType); if (null serviceDefinition) { return null; } if (_isRootScope serviceDefinition.ServiceLifetime ServiceLifetime.Scoped) { throw new InvalidOperationException($can not get scope service from the root scope, serviceType: {serviceType.FullName}); } if (serviceDefinition.ServiceLifetime ServiceLifetime.Singleton) { var svc _singletonInstances.GetOrAdd(serviceType, (t) GetServiceInstance(t, serviceDefinition)); return svc; } else if (serviceDefinition.ServiceLifetime ServiceLifetime.Scoped) { var svc _scopedInstances.GetOrAdd(serviceType, (t) GetServiceInstance(t, serviceDefinition)); return svc; } else { var svc GetServiceInstance(serviceType, serviceDefinition); if (svc is IDisposable) { _transientDisposables.Add(svc); } return svc; } }
}为了使得服务注册更加方便可以写一些扩展方法来方便注册public static IServiceContainer AddSingletonTService([NotNull]this IServiceContainer serviceContainer, [NotNull]TService service)
{ serviceContainer.Add(new ServiceDefinition(service, typeof(TService))); return serviceContainer;
}
public static IServiceContainer AddSingleton([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, ServiceLifetime.Singleton)); return serviceContainer;
}
public static IServiceContainer AddSingleton([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType, [NotNull]Type implementType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, implementType, ServiceLifetime.Singleton)); return serviceContainer;
}
public static IServiceContainer AddSingletonTService([NotNull]this IServiceContainer serviceContainer, [NotNull]FuncIServiceProvider, object func)
{ serviceContainer.Add(ServiceDefinition.SingletonTService(func)); return serviceContainer;
}
public static IServiceContainer AddSingletonTService([NotNull]this IServiceContainer serviceContainer)
{ serviceContainer.Add(ServiceDefinition.SingletonTService()); return serviceContainer;
}
public static IServiceContainer AddSingletonTService, TServiceImplement([NotNull]this IServiceContainer serviceContainer) where TServiceImplement : TService
{ serviceContainer.Add(ServiceDefinition.SingletonTService, TServiceImplement()); return serviceContainer;
}
public static IServiceContainer AddScoped([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, ServiceLifetime.Scoped)); return serviceContainer;
}
public static IServiceContainer AddScoped([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType, [NotNull]Type implementType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, implementType, ServiceLifetime.Scoped)); return serviceContainer;
}
public static IServiceContainer AddScopedTService([NotNull]this IServiceContainer serviceContainer, [NotNull]FuncIServiceProvider, object func)
{ serviceContainer.Add(ServiceDefinition.ScopedTService(func)); return serviceContainer;
}
public static IServiceContainer AddScopedTService([NotNull]this IServiceContainer serviceContainer)
{ serviceContainer.Add(ServiceDefinition.ScopedTService()); return serviceContainer;
}
public static IServiceContainer AddScopedTService, TServiceImplement([NotNull]this IServiceContainer serviceContainer) where TServiceImplement : TService
{ serviceContainer.Add(ServiceDefinition.ScopedTService, TServiceImplement()); return serviceContainer;
}
public static IServiceContainer AddTransient([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, ServiceLifetime.Transient)); return serviceContainer;
}
public static IServiceContainer AddTransient([NotNull]this IServiceContainer serviceContainer, [NotNull]Type serviceType, [NotNull]Type implementType)
{ serviceContainer.Add(new ServiceDefinition(serviceType, implementType, ServiceLifetime.Transient)); return serviceContainer;
}
public static IServiceContainer AddTransientTService([NotNull]this IServiceContainer serviceContainer, [NotNull]FuncIServiceProvider, object func)
{ serviceContainer.Add(ServiceDefinition.TransientTService(func)); return serviceContainer;
}
public static IServiceContainer AddTransientTService([NotNull]this IServiceContainer serviceContainer)
{ serviceContainer.Add(ServiceDefinition.TransientTService()); return serviceContainer;
}
public static IServiceContainer AddTransientTService, TServiceImplement([NotNull]this IServiceContainer serviceContainer) where TServiceImplement : TService
{ serviceContainer.Add(ServiceDefinition.TransientTService, TServiceImplement()); return serviceContainer;
}通过上面的代码就可以实现基本依赖注入了但是从功能上来说上面的代码只支持获取单个服务的实例不支持注册一个接口的多个实现获取接口的所有实现为此对 ServiceContainer 中的 Instance 的 ConcurrentDictionary 的 Key 进行一下改造使得可以能够以接口类型和实现类型联合作为 key为此就有了第二版的 ServiceContainerServiceContainer v2为此定义了一个 ServiceKey 的类型请注意这里一定要重写 GetHashCode 方法private class ServiceKey : IEquatableServiceKey
{ public Type ServiceType { get; } public Type ImplementType { get; } public ServiceKey(Type serviceType, ServiceDefinition definition) { ServiceType serviceType; ImplementType definition.GetImplementType(); } public bool Equals(ServiceKey other) { return ServiceType other?.ServiceType ImplementType other?.ImplementType; } public override bool Equals(object obj) { return Equals((ServiceKey)obj); } public override int GetHashCode() { var key ${ServiceType.FullName}_{ImplementType.FullName}; return key.GetHashCode(); }
}第二版的 ServiceContainer :public class ServiceContainer : IServiceContainer
{ internal readonly ConcurrentBagServiceDefinition _services; private readonly ConcurrentDictionaryServiceKey, object _singletonInstances; private readonly ConcurrentDictionaryServiceKey, object _scopedInstances; private ConcurrentBagobject _transientDisposables new ConcurrentBagobject(); private class ServiceKey : IEquatableServiceKey { public Type ServiceType { get; } public Type ImplementType { get; } public ServiceKey(Type serviceType, ServiceDefinition definition) { ServiceType serviceType; ImplementType definition.GetImplementType(); } public bool Equals(ServiceKey other) { return ServiceType other?.ServiceType ImplementType other?.ImplementType; } public override bool Equals(object obj) { return Equals((ServiceKey)obj); } public override int GetHashCode() { var key ${ServiceType.FullName}_{ImplementType.FullName}; return key.GetHashCode(); } } private readonly bool _isRootScope; public ServiceContainer() { _isRootScope true; _singletonInstances new ConcurrentDictionaryServiceKey, object(); _services new ConcurrentBagServiceDefinition(); } private ServiceContainer(ServiceContainer serviceContainer) { _isRootScope false; _singletonInstances serviceContainer._singletonInstances; _services serviceContainer._services; _scopedInstances new ConcurrentDictionaryServiceKey, object(); } public IServiceContainer Add(ServiceDefinition item) { if (_disposed) { throw new InvalidOperationException(the service container had been disposed); } if (_services.Any(_ _.ServiceType item.ServiceType _.GetImplementType() item.GetImplementType())) { return this; } _services.Add(item); return this; } public IServiceContainer TryAdd(ServiceDefinition item) { if (_disposed) { throw new InvalidOperationException(the service container had been disposed); } if (_services.Any(_ _.ServiceType item.ServiceType)) { return this; } _services.Add(item); return this; } public IServiceContainer CreateScope() { return new ServiceContainer(this); } private bool _disposed; public void Dispose() { if (_disposed) { return; } if (_isRootScope) { lock (_singletonInstances) { if (_disposed) { return; } _disposed true; foreach (var instance in _singletonInstances.Values) { (instance as IDisposable)?.Dispose(); } foreach (var o in _transientDisposables) { (o as IDisposable)?.Dispose(); } _singletonInstances.Clear(); _transientDisposables null; } } else { lock (_scopedInstances) { if (_disposed) { return; } _disposed true; foreach (var instance in _scopedInstances.Values) { (instance as IDisposable)?.Dispose(); } foreach (var o in _transientDisposables) { (o as IDisposable)?.Dispose(); } _scopedInstances.Clear(); _transientDisposables null; } } } private object GetServiceInstance(Type serviceType, ServiceDefinition serviceDefinition) { if (serviceDefinition.ImplementationInstance ! null) return serviceDefinition.ImplementationInstance; if (serviceDefinition.ImplementationFactory ! null) return serviceDefinition.ImplementationFactory.Invoke(this); var implementType (serviceDefinition.ImplementType ?? serviceType); if (implementType.IsInterface || implementType.IsAbstract) { throw new InvalidOperationException($invalid service registered, serviceType: {serviceType.FullName}, implementType: {serviceDefinition.ImplementType}); } if (implementType.IsGenericType) { implementType implementType.MakeGenericType(serviceType.GetGenericArguments()); } var ctorInfos implementType.GetConstructors(BindingFlags.Instance | BindingFlags.Public); if (ctorInfos.Length 0) { throw new InvalidOperationException($service {serviceType.FullName} does not have any public constructors); } ConstructorInfo ctor; if (ctorInfos.Length 1) { ctor ctorInfos[0]; } else { // TODO: try find best ctor ctor ctorInfos .OrderBy(_ _.GetParameters().Length) .First(); } var parameters ctor.GetParameters(); if (parameters.Length 0) { // TODO: cache New Func return Expression.LambdaFuncobject(Expression.New(ctor)).Compile().Invoke(); } else { var ctorParams new object[parameters.Length]; for (var index 0; index parameters.Length; index) { var parameter parameters[index]; var param GetService(parameter.ParameterType); if (param null parameter.HasDefaultValue) { param parameter.DefaultValue; } ctorParams[index] param; } return Expression.LambdaFuncobject(Expression.New(ctor, ctorParams.Select(Expression.Constant))).Compile().Invoke(); } } public object GetService(Type serviceType) { if (_disposed) { throw new InvalidOperationException($can not get scope service from a disposed scope, serviceType: {serviceType.FullName}); } var serviceDefinition _services.LastOrDefault(_ _.ServiceType serviceType); if (null serviceDefinition) { if (serviceType.IsGenericType) { var genericType serviceType.GetGenericTypeDefinition(); serviceDefinition _services.LastOrDefault(_ _.ServiceType genericType); if (null serviceDefinition) { var innerServiceType serviceType.GetGenericArguments().First(); if (typeof(IEnumerable).MakeGenericType(innerServiceType) .IsAssignableFrom(serviceType)) { var innerRegType innerServiceType; if (innerServiceType.IsGenericType) { innerRegType innerServiceType.GetGenericTypeDefinition(); } // var list new Listobject(4); foreach (var def in _services.Where(_ _.ServiceType innerRegType)) { object svc; if (def.ServiceLifetime ServiceLifetime.Singleton) { svc _singletonInstances.GetOrAdd(new ServiceKey(innerServiceType, def), (t) GetServiceInstance(innerServiceType, def)); } else if (def.ServiceLifetime ServiceLifetime.Scoped) { svc _scopedInstances.GetOrAdd(new ServiceKey(innerServiceType, def), (t) GetServiceInstance(innerServiceType, def)); } else { svc GetServiceInstance(innerServiceType, def); if (svc is IDisposable) { _transientDisposables.Add(svc); } } if (null ! svc) { list.Add(svc); } } var methodInfo typeof(Enumerable) .GetMethod(Cast, BindingFlags.Static | BindingFlags.Public); if (methodInfo ! null) { var genericMethod methodInfo.MakeGenericMethod(innerServiceType); var castedValue genericMethod.Invoke(null, new object[] { list }); if (typeof(IEnumerable).MakeGenericType(innerServiceType) serviceType) { return castedValue; } var toArrayMethod typeof(Enumerable).GetMethod(ToArray, BindingFlags.Static | BindingFlags.Public) .MakeGenericMethod(innerServiceType); return toArrayMethod.Invoke(null, new object[] { castedValue }); } return list; } return null; } } else { return null; } } if (_isRootScope serviceDefinition.ServiceLifetime ServiceLifetime.Scoped) { throw new InvalidOperationException($can not get scope service from the root scope, serviceType: {serviceType.FullName}); } if (serviceDefinition.ServiceLifetime ServiceLifetime.Singleton) { var svc _singletonInstances.GetOrAdd(new ServiceKey(serviceType, serviceDefinition), (t) GetServiceInstance(t.ServiceType, serviceDefinition)); return svc; } else if (serviceDefinition.ServiceLifetime ServiceLifetime.Scoped) { var svc _scopedInstances.GetOrAdd(new ServiceKey(serviceType, serviceDefinition), (t) GetServiceInstance(t.ServiceType, serviceDefinition)); return svc; } else { var svc GetServiceInstance(serviceType, serviceDefinition); if (svc is IDisposable) { _transientDisposables.Add(svc); } return svc; } }
}这样我们就不仅支持了 IEnumerableTService 的注册也支持 IReadOnlyListTService/ IReadOnlyCollectionTService 的注册因为 GetService 返回是 object , 不是强类型的所以为了使用起来方便定义了几个扩展方法类似于微软的依赖注入框架里的 GetServiceTService()/ GetServicesTService()/ GetRequiredServiceTService()/// summary
/// ResolveService
/// /summary
/// typeparam nameTServiceTService/typeparam
/// param nameserviceProviderserviceProvider/param
/// returns/returns
public static TService ResolveServiceTService([NotNull]this IServiceProvider serviceProvider) (TService)serviceProvider.GetService(typeof(TService));
/// summary
/// ResolveRequiredService
/// throw exception if can not get a service instance
/// /summary
/// typeparam nameTServiceTService/typeparam
/// param nameserviceProviderserviceProvider/param
/// returns/returns
public static TService ResolveRequiredServiceTService([NotNull] this IServiceProvider serviceProvider)
{ var serviceType typeof(TService); var svc serviceProvider.GetService(serviceType); if (null svc) { throw new InvalidOperationException($service had not been registered, serviceType: {serviceType}); } return (TService)svc;
}
/// summary
/// Resolve services
/// /summary
/// typeparam nameTServiceTService/typeparam
/// param nameserviceProviderserviceProvider/param
/// returns/returns
public static IEnumerableTService ResolveServicesTService([NotNull]this IServiceProvider serviceProvider) serviceProvider.ResolveServiceIEnumerableTService();More后面还更新了一版主要优化性能目前来说还不太满意暂时这里先不提了ReferenceDynamic Casting using Reflectionhttps://github.com/WeihanLi/WeihanLi.Common/blob/dev/test/WeihanLi.Common.Test/DependencyInjectionTest.cs