コントロールの1.反転
依存は1.1とは何ですか?
依存オブジェクト指向の概念は、クラスとクラスの間の関係を記述するために使用されます。主に例えば2つのオブジェクト間の2つの独立したオブジェクト、オブジェクトのインスタンスが他のオブジェクトの構成のために責任がある、または別のオブジェクトのサービスに依存して、依存関係
1.2制御の反転とは何ですか?
彼はあるその依存オブジェクトを作成するために、アクティブなプログラム、あるプログラム、内のオブジェクトを作成するためにコンストラクタを使用して新しいキーワードを使用して、最初は「前進」、と言って伝統を反転させると「フォワード。」
呼び出し側は、彼が、発信者だったことオブジェクトを作成しませんが、オブジェクトの呼び出し側が作成した第三者(コンテナ)、プロセスと呼ばれることにより、制御の反転(制御の反転、IOC)。
なぜ、制御の反転?オブジェクト指向プログラミングの制御設計原理の反転は、後のメンテナンスを展開することが容易で、コンピュータ・コードとの間の結合の程度を減少させるために使用することができます。
1.3依存性注入とは何ですか?
制御の反転達成するための主な方法依存性注入を。(もちろん、これは、より多くの方法依存注射、ならびに依存ルックアップ(依存ルックアップ、DL)よりも両者の差を指す:定義:制御の反転)
特に、依存性注入:クラスは自動的に依存オブジェクトを作成しません呼び出すが、ヘルプに容器の使用を作成し、依存オブジェクト注入し、このプロセスが呼び出される依存性注入(依存性注入、DI)
具体的には:(依存オブジェクト)で使用されるタイプのクラスB、クラスA(発呼クラス)のオブジェクト、通常の状況下で、我々は、クラスA、クラスB内にコンストラクタを作成するために、新たなキーワードとオブジェクトを使用
しかし、DI技術を使用した後、クラスAのみタイプBクラスのプロパティを定義する必要があり、この必要性は、直接新しいオブジェクトを得ることができないが、オブジェクトがされるクラスBの新しいタイプの外部アウトIOCコンテナによって及び注入にクラスAにクラスAとクラスBを達成するために、参照デカップリングを。
1.4簡単な概要
上記の概念を参照し、フレーズ「ことを理解することができる制御の反転と呼ばれるインスタンス化マネージャプログラム内側から外側に述べたモジュール間の依存関係、このプロセスがインスタンス化依存性注入と呼ばれています。」
コントロールのコンテナの2反転
2.1 IOCコンテナ説明
それは制御の反転に来るとき、「呼び出し元のクラスと注入クラスへの外部コールに依存するオブジェクトを作成するために、IOCコンテナの使用」を参照し、IOCのコンテナはどのようなどこにいるの?
IOCコンテナは、依存性注入機能、IOCコンテナインスタンス化位置、およびアプリケーション構成内のオブジェクト間のオブジェクトの依存関係を有する容器です。したがって、アプリケーションが直接IOCコンテナによってコード、アプリケーションアセンブリに関連する新しいオブジェクトを必要としません。
要するに、2つの主な機能上のIOC容器:1、およびサービスインスタンスの間の結合関係。2、インスタンスの作成と破棄
このようユニティ、AutoFac、Spring.netなどの.NETプログラムの多くのIOCコンテナ、で。
これは、.NET程度AutoFac最も人気のあるIOCコンテナ、この記事で使用の簡単なルックAutoFac言われています。
2.2導入事例AutoFac
使用AutoFacコンテナは、一般的にされたインタフェースを指向プログラミング。だからここにいることを、使用AutoFacを証明するために、階層的プロジェクトを使用して使用AutoFacは、クラスインターフェイスのオブジェクトを作成します
新しいクラスライブラリプロジェクトを作成しますTestIBLL①
インターフェイスを定義します
public interface IUserBll
{
//检查登录信息
bool Login(string userName, string pwd);
//添加新用户
void AddNew(string userName, string pwd);
}
新しいクラスライブラリプロジェクトを作成しますTestBLLImpl②
実装クラスのインターフェイス定義のTestIBLLプロジェクトへの参照を追加します
public class UserBll : IUserBll
{
//实现接口
public void AddNew(string userName, string pwd)
{
Console.WriteLine($"新增了一个用户:{userName}");//为了演示,简单模拟
}
public bool Login(string userName, string pwd)
{
Console.WriteLine($"登录用户是:{userName}");//为了演示,简单模拟
return true;
}
}
[説明]:
本明細書で定義されるUserBll
クラス実装するIUserBll
インタフェース、
従っAutoFacの用語では、アドレスに続きます:
UserBll
クラスと呼ばれる部品(コンポーネント)IUserBll
インターフェイスは、呼び出されたサービス(サービス)
③新しいコンソールプロジェクトを作成しますTestUI
UI層のためのシミュレーション
TestIBLLとTestBLLImplプロジェクトへの参照を追加します。
インストールAutoFac:PM>Install-Package Autofac
static void Main(string[] args)
{
//创建容器构造者
ContainerBuilder builder = new ContainerBuilder();
//注册组件UserBll类,并把服务IUserBll接口暴露给该组件
//把服务(IUserBll)暴露给组件(UserBll)
builder.RegisterType<UserBll>().As<IUserBll>();
//创建容器
IContainer container = builder.Build();
//使用容器解析服务,创建实例(不推荐,见下面说明):IUserBll userBll = container.Resolve<IUserBll>();
//使用生命周期解析服务,创建实例
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
IUserBll userBll = scope.Resolve<IUserBll>();
userBll.Login("shanzm", "123456");
}
}
[説明]:
前記AutoFacの用語:
- 容器(コンテナ):プログラムの構造は、すべてのコンポーネントを管理するために使用される(単に手段をその実装クラスのすべてのインタフェース)
- ライフサイクル(寿命):放出の持続時間のインスタンスを作成するから
- 登録(登録):コンテナの振る舞いに追加および設定のコンポーネント
- 有効範囲(スコープ):特定のコンテキスト、アセンブリの他の構成要素は、それらの共有サービスに基づいて行われる場合において
- 解決サービス:サービスは、オブジェクトのインスタンスと等価です
- レジスタ:コンテナの実装サービスを追加する(インタフェース)成分(実装クラス)操作
作成することにより
ContainerBuilder
レジスタコンポーネントをContainerBuilder
ここで使用される登録方法の数は、登録の種類によってですがありますRegisterType()
。どんなことで
RegisterType()
コンポーネントの登録Autofacは、あなたが登録したオブジェクトのインスタンスを作成しますと、解決サービスのバックの特定の型である必要があります各コンポーネントは 1つのまたは複数に露出しているサービス(以下、単にクラスである(アセンブリ)、1つまたは複数のインターフェイス(サービス)を実装することができる)、ContainerBuilder()メソッドとしてのそれらの使用は、一緒に接続します。
解決サービス、オブジェクトを提供するサービスの作成(単にインタフェースが登録実装クラスとして作成されていることを意味します)
ない解決するには、直接コンテナサービスを使用することをお勧めします:
IUserBll userBll = container.Resolve<IUserBll>();
私は解決サービスへのコンテナを使用して、いくつかの記事やビデオを見て、私はそれがメモリリークを引き起こす可能性があるため、このような使用は推奨されていない公式の文書をお読みください。
あなたは、常にサービスインスタンスが適切に解放されることを保証するために、ライフサイクル分析サービス(すなわち、道の私の例)から推奨とガベージコレクション
AutoFacドキュメント:「フォーエバースコープライフサイクル分析サービスから代わりのルートコンテナから!」
簡潔サンプルコードのために従ってください、私は解決するには、直接コンテナサービスを使用し、それが知られています!
3使用AutoFacいくつかの詳細
以下AutoFac AutoFacのドキュメントを参照してください、あなたの最も基本的なAPI、具体的な内容や他の機能のいくつかを示して、そのドキュメントは非常に詳述されていると中国語版(あるAutoFac文書が)
3.1準備
そして、上記の例では、以下の項目TestIBLLインタフェースライブラリを追加します。
IAnimalBll.csを作成します
//IAnimalBll接口
public interface IAnimalBll
{
void Cry();//动物都有叫的动作
}
IMasterBll.csを作成します
//IMasterBll接口
public interface IMasterBll
{
void Walk();
}
上記インターフェースでクラスライブラリプロジェクトTestBLLImplに実装されています
DogBll.csを作成します
//DogBll类实现IAnimalBll接口
public class DogBll : IAnimalBll
{
public void Cry()
{
Console.WriteLine("汪汪汪!");
}
}
CatBll.csを作成します
//CatBll类实现IAnimalBll接口
public class CatBll : IAnimalBll
{
public void Cry()
{
Console.WriteLine("喵喵喵!");
}
}
MasterBll.csを作成します
//MasterBll类,实现了IMasterBll接口和IUserBll接口
public class MasterBll : IMasterBll,IUserBll
{
//注意这里,MasterBll是接口的实现类,这个类还有一个接口类型的属性
public IAnimalBll dogBll { get; set; }
public void AddNew(string userName, string pwd)
{
Console.WriteLine($"新增了一个Master用户:{userName}");
}
public bool Login(string userName, string pwd)
{
Console.WriteLine($"登录用户是Master:{userName}");
return true;
}
public void Walk()
{
Console.WriteLine("带着狗散步!");
dogBll.Cry();//在调用中,使用.PropertiesAutowired()方法给dogBll注册其实现类
}
}
3.2すべては、アセンブリ全体の実装クラスを登録しました
プロジェクトでは、実際には、我々が使用することができ.RegisterAssemblyTypes()
、適切なインターフェイスに登録されているアセンブリのすべてのクラスへのワンタイム・インターフェース(クラスライブラリプロジェクトを)
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();//创建容器构造者
Assembly asm = Assembly.Load(" TestBLLImpl");//获取指定的程序集
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();//注册指定程序集中的所有接口实现类
IContainer container = builder.Build();//创建容器
IUserBll userBll = container.Resolve<IUserBll>();//解析服务,创建实例
userBll.Login("shanzm", "123456");//使用服务提供者
}
[説明]:
使用上の
.RegisterAssemblyTypes()
指定されたアセンブリスキャンレジスタの使用Where()
およびExcept()
フィルタリングするタイプ
の特定の使用は見ることが国会のスキャン:ドキュメントを.AsImplementedInterfaces()
:それは実装して、すべてのインターフェイスへのプログラムの実装クラス登録の焦点。
3.3注入インターフェースクラスインターフェースタイプ属性
実装クラスの特性も、AutoFacを注入に使用することができます
プロパティのインターフェイスタイプのインターフェイスがある場合に実装するクラスのために、我々は、使用することができ.PropertiesAutowired()
、実装クラスは、プロパティの登録ながら、すなわち、自動組立特性を達成するためにいる間、すなわち特性注入をレジスタ
static void Mian(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
Assembly asm = Assembly.Load("TestBLLImpl");
//在这里通过.PropertiesAutowired(),给接口实现类中的接口属性也注册一个该类型的接口的实现类,即实现属性自装配
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
builder.RegisterType<DogBll>().As<IAnimalBll>();
IContainer container = builder.Build();
IMasterBll masterBll = container.Resolve<IMasterBll>();
masterBll.Walk();//打印:带着狗散步!汪汪汪!
}
詳しくは、中にいることを注意
MasterBll
クラスのIAnimalBll
属性の種類dogBll
、我々が使用するPropertiesAutowired()
プロパティを自動的に組み立てる方法を、しかしIAnimalBllインタフェース、死ぬ
TestBLLImpl程序集
2つの実装クラスが自動的にdogBll属性登録がオブジェクト型CatBllで組み立てるためには、そこにありますそして、私の期待はIAnimalBllにプロパティの種類のオブジェクトDogBllタイプを登録されています
だからここにもIAnimalBllインターフェイスにDogBllクラスの登録を示してい
あなたは、事前に施設の名前と値がわかっている場合は、使用することができます
WithProperty("PropertyName", propertyValue)
だから、例が書くかもしれません。
builder.RegisterType<MasterBll>().As<IMasterBll>().WithProperty("dogBll",new DogBll());
3.4インターフェースについて異なるインプリメンテーション・クラスの数を持っています
時間は、我々は与えられた各登録名を提供することができる、インターフェースクラスの複数の実装を有していてもよく、インタフェースの実装クラスへの登録のために来ている
builder.RegisterType<Object>().Named<IObject>(string name)
ネームサービスプロバイダ(実装クラス)を指定して作成することができる解決サービスの時、
IContainer.ResolveNamed<IObject>(string name)
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
//builder.RegisterType<DogBll>().As<IAnimalBll>();//这样写,下面注册服务的时候,你只能给IAnimalBll对象创建一个DogBll类型的实例
builder.RegisterType<DogBll>().Named<IAnimalBll>("Dog");
builder.RegisterType<CatBll>().Named<IAnimalBll>("Cat");
IContainer container = builder.Build();
using (ILifetimeScope scope = container.BeginLifetimeScope())
{
IAnimalBll dogBll = scope.ResolveNamed<IAnimalBll>("Dog");
IAnimalBll catBll = scope.ResolveNamed<IAnimalBll>("Cat");
dogBll.Cry();
catBll.Cry();
}
}
登録がそれにインターフェースクラスのどの異なる実装されている場合しかし、我々は、実装クラスのアセンブリ全体を登録しましたか?
使用IEnumerable<IObject> objects =container.Resolve<IEnumerable<IObject>>()
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
Assembly asm = Assembly.Load(" TestBLLImpl");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
IContainer container = builder.Build();
//解析服务,将所有实现了IAnimalBll接口的类都注册,结果存放在集合中
IEnumerable<IAnimalBll> animalBlls = container.Resolve<IEnumerable<IAnimalBll>>();
foreach (var bll in animalBlls)
{
Console.WriteLine(bll.GetType());
bll.Cry();
}
//选取指定的实现类
IAnimalBll dogBll = animalBlls.Where(t => t.GetType() == typeof(DogBll)).First();
dogBll.Cry();
}
約3.5クラスを実装し、複数のインターフェイスを実現します
我々は、登録コンポーネント、複数のサービスにさらされる部品に使用された場合、あなたが継続的に使用できると言う前に、.As()
方法を
使用して、.AsImplementedInterfaces()
同じ効果を得ることができます
MasterBllクラスが実装複数のインタフェース、我々は彼のすべてに、クラスのインターフェイスを登録することができます
限りMasterBllインタフェースは、我々は彼に型のオブジェクト与えるMasterBll登録して、実装されるような、言葉
MasterBllオブジェクトは、現在のインターフェイスが含まれていること、しかし、注意を方法
static void Mian(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
//builder.RegisterType<MasterBll>().As<IUserBll>().As<IMasterBll>();
//即一个组件暴露了多个服务,这里就等价于:
builder.RegisterType<MasterBll>().AsImplementedInterfaces();//把MasterBll类注册给所有他实现的接口
IContainer container = builder.Build();
//解析IUserBll服务
//其实这里的userBll是MasterBll类型的对象,但是这个MasterBll类型的对象只具有IUserBll接口中的方法,不具有IMasterBll接口中的方法
IUserBll userBll = container.Resolve<IUserBll>();
userBll.Login("shanzm", "11111");//打印:登录用户是Master:shanzm
Console.WriteLine(userBll.GetType());//打印:TestBLLImpl.MasterBll
//userBll.Walk();//注意虽然是MasterBll类型对象,但是只具有当前解析的IUserBll接口中的方法
}
[説明]:
登録コンポーネント(実装クラス)の時点での連続使用
As()
方法、すべてのインターフェイス(サービス)の実装、あまりにも多くの問題を公開するので、使用できる.AsImplementedInterfaces()
すべてのインターフェイスを実装するための方法は、自分のクラスを達成するために登録しました実装クラスは、現在唯一の方法で未解決のインターフェースと、複数のインタフェースを実装するが、解決サービスの時。
スコープの例については3.6
AutoFac、最終的な解決サービスを使用する場合は、提供されるサービスのインスタンスを作成します
サービスと呼ばれる時間にインスタンス化からの最後のリリースであるオブジェクトは、プログラム内に存在する時間の長さ、ライフサイクル、
アプリケーション内のオブジェクトは、サービスと呼ばれる、他の構成要素および消費者の範囲と共有することができる範囲
上記の概念を理解した後、私たちは何であるか説明できる範囲の例
1.依存(インスタンスごとに依存)の一例
我々は解決(呼び出すとき)分析サービスのインスタンスを返し、各要求は固有のインスタンスを返し、説明もなく、これはデフォルトのスコープです!
static void Mian(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
//注册实例
//builder.RegisterType<UserBll>().As<IUserBll>().InstancePerDependency(); //默认就是这种
builder.RegisterType<UserBll>().As<IUserBll>();
//创建容器
IContainer container = builder.Build();
//解析服务
using (var scope = container.BeginLifetimeScope())
{
IUserBll userBll1 = scope.Resolve<IUserBll>();
userBll1.Login("shanzm", "1111");//打印:登录用户是普通用户:shanzm
IUserBll userBll2 = scope.Resolve<IUserBll>();
userBll2.Login("shanzm", "2222");//打印:登录用户是普通用户:shanzm
Console.WriteLine(ReferenceEquals(userBll1, userBll2));//打印结果:false
}
}
//说明:根据调试,结果就可以看出,每次在解析服务,创建的服务提供者都是新的。
//你要注意,我们上面的示例代码在同一个生命周期中注册的两个IUserBll接口的实例,但是它们依旧是两个不同的实例
例2.シングル(単一インスタンス)
また「一実施形態」と呼ばれる単一インスタンスのスコープ、ルート内のすべての要求と、すべてのコンテナは、ネストされたスコープが同じインスタンスを返しますです。
指向プログラミング・インターフェースの推奨は、実施例の範囲は、使用:単一インスタンス。汚れが生じ、同時動作を防ぎます!
static void Mian(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
//注册实例
builder.RegisterType<UserBll>().As<IUserBll>().SingleInstance();//设置为单一实例
//创建容器
IContainer container = builder.Build();
//解析服务
using (var scope1 = container.BeginLifetimeScope())
{
IUserBll userBll1 = scope1.Resolve<IUserBll>();
userBll1.Login("shanzm", "1111");
using (var scope2 = container.BeginLifetimeScope())
{
IUserBll userBll2 = scope2.Resolve<IUserBll>();
userBll2.Login("shanzm", "2222");
Console.WriteLine(ReferenceEquals(userBll1, userBll2));
//因为是单一实例,所以就是在不同的生命周期中,也是同一个实例,打印结果:true
}
}
}
//说明:最终的打印结果:true 。即使在不同的生命周期中每次在解析服务,创建的服务提供者都是同一个!
基準とすることができる範囲の他の例は、例スコープ:ドキュメント
- スコープのライフサイクルの各インスタンス(インスタンスごとに生涯スコープ)
- 各ライフサイクル・スコープ・インスタンスと一致する(インスタンスごとにマッチング寿命スコープ)
- リクエストの各インスタンス(インスタンスごとリクエスト)
- インスタンス(インスタンスごとに所有)しているたびに
- スコープスレッド(スレッドスコープ)
MVC 4. AutoFac
ASP .NET MVCで使用する方が便利AutoFac、主な場所はAutoFacための注意Global.asax.cs設定ファイルを必要としています
簡単な例を作る:( 完全なソースコードのデモをダウンロードするにはクリック)
①TestIServiceという名前のクラスライブラリプロジェクト、すべてのインターフェイスの定義を作成します。
ファイルを作成しますIUserService.cs
public interface IUserService
{
bool CheckLogin(string userName, string pwd);
bool CheckUserNameExists(string userName);
}
ファイルを作成しますINewsService.cs
public interface INewsService
{
string AddNews(string title, string body);
}
②TestServiceImplは、クラス定義のインタフェースを実現するという名前のクラスライブラリプロジェクトを作成します。
まず、プロジェクトTestIServiceへの参照を追加します
ファイルを作成しますUserService.cs
public class UserService : IUserService
{
//注意接口的实现类是可以有接口类型的属性,该属性也会被注册一个实现对应类型接口的类的对象
public INewsService newsService { get; set; }
public bool CheckLogin(string userName, string pwd)
{
return true;
}
public string UserAction(string userName)
{
string result = newsService.AddNews("2020年3月16日-新冠病毒", "中国境内的新冠病毒被有效遏制");
return userName+" 添加新闻 :"+result;
}
}
ファイルを作成しますNewsService.cs
public class NewsService : INewsService
{
public string AddNews(string title, string body)
{
return ($"Title:{title},Content:{body}");
}
}
③TestMVCと呼ばれるWeb MVCプロジェクトを作成します
まず、TestIServiceプロジェクトやプロジェクトへの参照を追加TestServiceImpl
そして、プラグインMVC AutoFacをインストールします。PM> Install-Package AutoFac.Mvc5
Global.asax.csで構成AutoFacを追加します。
using Autofac.Integration.Mvc;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
/*------------------------------AutoFac配置--开始--------------*/
ContainerBuilder builder = new ContainerBuilder();
//此处需要:using Autofac.Integration.Mvc;
//把当前程序集中的所有Controllerr类中的接口类型的属性注册
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
Assembly asmSevice = Assembly.Load("TestServiceImpl");
builder.RegisterAssemblyTypes(asmSevice)
.Where(type => !type.IsAbstract)//除去抽象类,抽象类不可以实例化(其实这一句也可以不写)
.AsImplementedInterfaces()//将实现类注册给其实现的所有接口
.PropertiesAutowired();//接口实现类中接口类型的属性也注册
IContainer container = builder.Build();
//MVC中的所有Controller类都是由AutoFac帮我们创建对象
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
/*------------------------------AutoFac配置--结束--------------*/
}
HomeController.csコントローラを作成します
public class HomeController : Controller
{
public IUserService userService { get; set; }//通过AutoFac自动为我们赋值一个IUserService接口实现对象
public ActionResult CheckLogin()
{
bool b = userService.CheckLogin("shanzm", "123456");
return Content(b.ToString());//结果:页面显示true
}
public ActionResult UserAddNews()
{
string result = userService.UserAction("shanzm");
return Content(result);//结果:页面显示:shanzm 添加新闻 :Title:2020年3月16日-新冠病毒,Content:中境内的新冠病毒被有效遏制
}
}
ブラウザの要求であることを、あなたは私たちが適切なインスタンスの属性の成功を注入するAutoFac UserServiceのを使用していることがわかります、にHomeController 2アクションでした!
リファレンスおよびサンプルソースコードのダウンロード
パークブログ:ASP.NET MVC IOCのAutoFacレイダース