依存性注入原則分析ABP
会場をご参照ください。3.依存性注入とインターセプター- [ABP vNextソースコード解析]補数と、この記事の完全な紙。
ABP最後依存性注入は、方法IConventionalRegister AddTypeのインタフェースによって達成されます。このインタフェースを見てください:
public interface IConventionalRegistrar
{
void AddAssembly(IServiceCollection services, Assembly assembly);
void AddTypes(IServiceCollection services, params Type[] types);
void AddType(IServiceCollection services, Type type);
}
このインターフェースは、実際には、支持アセンブリ着信三つの方法、配列型、特定の種類を定義する、抽象クラス今== ConventionalRegistrarBase ==で:
public abstract class ConventionalRegistrarBase : IConventionalRegistrar
{
public virtual void AddAssembly(IServiceCollection services, Assembly assembly)
{
var types = AssemblyHelper
.GetAllTypes(assembly)
.Where(
type => type != null &&
type.IsClass &&
!type.IsAbstract &&
!type.IsGenericType
).ToArray();
AddTypes(services, types);
}
public virtual void AddTypes(IServiceCollection services, params Type[] types)
{
foreach (var type in types)
{
AddType(services, type);
}
}
public abstract void AddType(IServiceCollection services, Type type);
}
、アセンブリ、または配列のタイプは、最終的にAddTypeのメソッドを呼び出すかどうかを派生クラスでこの抽象クラスでAddTypeの実装、ABPは、デフォルトの実装クラス== AddTypeのメソッドを実装DefaultConventionalRegistrar ==、ABP依存性を有しますAddTypeのクラスの注入法により注入されます。出典:
public class DefaultConventionalRegistrar : ConventionalRegistrarBase
{
public override void AddType(IServiceCollection services, Type type)
{
if (IsConventionalRegistrationDisabled(type))
{
return;
}
var dependencyAttribute = GetDependencyAttributeOrNull(type);
var lifeTime = GetLifeTimeOrNull(type, dependencyAttribute);
if (lifeTime == null)
{
return;
}
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type);
TriggerServiceExposing(services, type, serviceTypes);
foreach (var serviceType in serviceTypes)
{
var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
if (dependencyAttribute?.ReplaceServices == true)
{
services.Replace(serviceDescriptor);
}
else if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
else
{
services.Add(serviceDescriptor);
}
}
}
// 其他方法实现
}
依存性の注入の実装のアイデアABPこのクラスからわかるように:構築物サービス記述子へのサービスタイプGetExposedServicesメソッドによって返されたリストに基づいて、(サービスの最初の記述パラメータは、2番目のパラメータはタイプの実現である、サービスの種類です)。タイプは、私たちが注入さを達成したいタイプです。そして、サービス記述子のDIコンテナにこれを注入します。
GetDependencyAttributeOrNull方法とGetLifeTimeOrNullは、優先順位の高いので、もし依存性注入特性、デフォルトのライフサイクルを使用しない場合は、依存性の注入特性クラスとそのライフサイクルを慣れることです。GetExposedServices ExposedServiceExplorerは静的クラスで、クラスは、静的噴射型定義および実装を得るために使用されます。ソースは達成します:
public static List<Type> GetExposedServices(Type type)
{
return type
.GetCustomAttributes()
.OfType<IExposedServiceTypesProvider>()
.DefaultIfEmpty(DefaultExposeServicesAttribute)
.SelectMany(p => p.GetExposedServiceTypes(type))
.ToList();
}
インターフェイスの定義と実装IExposedServicveTypeProvider:
//定义:
public interface IExposedServiceTypesProvider
{
Type[] GetExposedServiceTypes(Type targetType);
}
//实现:
public class ExposeServicesAttribute : Attribute, IExposedServiceTypesProvider
{
public ExposeServicesAttribute(params Type[] serviceTypes)
{
ServiceTypes = serviceTypes ?? new Type[0];
}
public Type[] GetExposedServiceTypes(Type targetType)
{
var serviceList = ServiceTypes.ToList();
if (IncludeDefaults == true)
{
foreach (var type in GetDefaultServices(targetType))
{
serviceList.AddIfNotContains(type);
}
if (IncludeSelf != false)
{
serviceList.AddIfNotContains(targetType);
}
}
else if (IncludeSelf == true)
{
serviceList.AddIfNotContains(targetType);
}
return serviceList.ToArray();
}
private static List<Type> GetDefaultServices(Type type)
{
var serviceTypes = new List<Type>();
foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{
var interfaceName = interfaceType.Name;
if (interfaceName.StartsWith("I"))
{
interfaceName = interfaceName.Right(interfaceName.Length - 1);
}
if (type.Name.EndsWith(interfaceName))
{
serviceTypes.Add(interfaceType);
}
}
return serviceTypes;
}
}
インタフェースは、クラスの特徴である実装クラスExposeServices特性、に実装され、第一--ExposeServices噴射ABP注入特性及びサービスの三種類です。コンストラクタは直接サービスのリストの種類を注入するために保存されます。第二は、この方法は、サービスのデフォルトのタイプを返し、GetDefaultService方法です。反射クラスによって(Iインタフェース名を削除した後に)インタフェース、およびインターセプト名を継承して得られた唯一のインタフェースのクラス名と同じ条件の下でのインタフェースは、==ノートに、この時点実現されるサービスの種類の一覧==に注入されます!方法のこのタイプのサービスの種類がリスト(ServiceTypes)に追加される返します。==デフォルト実装クラス自体はに分析することができ、ソースコードから、==サービスタイプのリストの中に注入されます。
if (IncludeSelf != false)
{
serviceList.AddIfNotContains(targetType);
}
TargetTypeが、我々は現在、注入するタイプです。このタイプでは、それ自体が注入されます。このような利点は、あなたが直接もたらしたインスタンス化の依存を減らし、クラスのインスタンスを取得することができるということです。
彼らは注入型の定義と実装リスト(serviceTypes)に戻ったので、そのリストの中を歩く、サービスディスクリプタ(ServiceDescriptor)パラメータのサービス種別は、項目のリストがあります。サービス記述子には、DIコンテナの中に注入されます。パラメータがReplaceServicesであれば依存性注入特徴的な方法については、彼らが置き換えられます。登録パラメータ場合は、直接注入はなります。そうでない場合は、DIコンテナに直接添加します。
実装の注入方法の三種類:
- インジェクション分析ExposeServicesプロパティ
// 接口
public interface IMessageWriter
{
void Write();
}
// 实现 1
[ExposeServices(typeof(IMessageWriter))]
public class TestMessageTwo : IMessageWriter, ITransientDependency
{
public void Write()
{
Console.WriteLine("TestMessageTwo");
}
}
// 实现 2
[ExposeServices(typeof(IMessageWriter), typeof(TestMessageOne))]
public class TestMessageOne : IMessageWriter, ITransientDependency
{
public void Write()
{
Console.WriteLine("TestMessageOne");
}
}
// 注入
_services = new ServiceCollection();
_services.AddType<TestMessageOne>();
_services.AddType<TestMessageTwo>();
// 底层调用:
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type);
GetExposedServices ExposedServiceExplorer静的クラスメソッドによってABP底は、登録のタイプ定義および実装と判定する。この最後の事実は、静的クラスのコンストラクタが呼び出され、GetExposedServiceTypes方法ExposeServicesAttributeクラスは、サービスリストのタイプを決定されています。
public ExposeServicesAttribute(params Type[] serviceTypes)
{
ServiceTypes = serviceTypes ?? new Type[0];
}
public Type[] GetExposedServiceTypes(Type targetType)
{
}
- 依存性の注入特性
//接口
public interface IMyService : ITransientDependency
{
}
//实现
[Dependency(TryRegister = true)]
public class TryRegisterImplOfMyService : IMyService
{
}
//注入
_services = new ServiceCollection();
_services.AddTypes(typeof(TryRegisterImplOfMyService));
//底层调用
ExposeServicesAttribute.GetDefaultServices(typeof(TryRegisterImplOfMyService));
依存性注入特性GetDefaultServices方法は、次にAddTypeの方法DefaultConventionalRegistrarクラスで構成された呼び出しリストサービスタイプ、サービス記述子を返し、DIに注入されます。
var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
if (dependencyAttribute?.ReplaceServices == true)
{
services.Replace(serviceDescriptor);
}
else if (dependencyAttribute?.TryRegister == true)
{
services.TryAdd(serviceDescriptor);
}
注:
依存性注入と注入のインタフェースモードの場合、実装クラスのクラス名は、インタフェース名で終わる必要があり、そうでなければDIの中に注入されることはありません。
- インタフェース注入
//接口
public interface IMyService : ITransientDependency
{
}
//实现 1
public class FirstImplOfMyService : IMyService
{
}
//实现 2
public class SecondImplOfMyService : IMyService
{
}
// 注入
_services = new ServiceCollection();
_services.AddTypes(typeof(FirstImplOfMyService),typeof(SecondImplOfMyService));
//底层调用
ExposeServicesAttribute.GetDefaultServices(typeof(TryRegisterImplOfMyService));
その後、射出インタフェースモードでなく、リターンコールGetDefaultServicesタイプリスト、および反復、サービスタイプのリストに保存し、最後にDIコンテナに注入。
- あるいはReplaceServices
インタフェースモード依存性注入と注入特性であれば、それはケース別に同じインタフェースを使用し、例:
// 接口
public interface IMyService : ITransientDependency
{
}
// 接口方式实现
public class FirstImplOfMyService : IMyService
{
}
// Dependency特性注入 -- 替换掉 接口方式注入的实现
[Dependency(ReplaceServices = true)]
public class MyServiceReplacesIMyService : IMyService
{
}
// 注入
_services = new ServiceCollection();
_services.AddTypes(typeof(FirstImplOfMyService),typeof(MyServiceReplacesIMyService));
これは、インターフェイスの注入代替の実施形態の使用ReplaceServices依存性の注入特性を行います。したがって、唯一の噴射特性依存性DIは容器に添加します。
コード例:
#region ExposeServices 属性注入
public interface ICalculator { }
public interface ITaxCalculator { }
[ExposeServices(typeof(IService))]
public class TaxCalculator : ICalculator, ITaxCalculator, ITransientDependency
{
}
#endregion
#region 接口约定 模式注入
public interface IService : ITransientDependency { }
public class MyService : IService
{
}
#endregion
#region Dependency特性注入
public interface IMyDependencyTest { }
[Dependency(lifetime: ServiceLifetime.Transient, TryRegister = true)]
public class MyDependencyTest : IMyDependencyTest { }
#endregion
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddType(typeof(MyDependencyTest));
services.AddType(typeof(MyService));
services.AddType<TaxCalculator>();
foreach(var service in services)
{
Console.WriteLine($"{service.ServiceType} --- {service.ImplementationType} --- {service.Lifetime}");
}
Console.Read();
}
}
ExposeServices注入性の除去、他の二つのモードが名前に対応するクラスをインターフェイスしなければなりません。そうしないと、あなただけのクラス自体を注入、しかし、ExposeServicsプロパティが傍受インタフェース名とクラス名の比較を注入しないであろうことができます。
出力: