Open rainit2006 opened 7 years ago
ImportingConstructor 我们知道类的构造函数是可以重载的,我们通过构造函数可以向对象传递参数。那么如果我们的MEF也需要通过构造函数传参怎么办呢?别担心,有我们神奇的ImportingConstructor为您解决。
[ImportingConstructor]
public PowerManagerDomainService(IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
要求:IUserRepository 和 IRoleRepository 类型要有对应的Export。
这样在构造PowerManagerDomainService时会调用IUserRepository和IRoleRepository的构造函数。
[Export]
public sealed class A
{
}
[Export]
public sealed class B
{
[ImportingConstructor]
public B(A a)
{
}
}
Then you call container.GetExportedValue(), it will look in the catalog to find the export for B, then find the importing constructor, then try to resolve the import for A. Assuming that class A is part of your available exports (either added explicitly or, more typically, part of a catalog), it will then get the exported value of A (possibly constructing it) and use that to construct B.
2つ以上インスタンスが欲しいんだけど?:PartCreationPolicy属性指定 MEFでは、デフォルトだとコンテナ内でのインスタンスは1つということになります。ある意味シングルトンパターンみたいなことをしなくてもMEFのコンテナ内で勝手にシングルトンとして管理してくれるので有りがたい面もあります。しかし、全てがシングルトンだと困るということもあります。そういう時にどうするのか?というのを見てみましょう。
System.ComponentModel.Composition.PartCreationPolicyAttribu: Exportされたクラスのインスタンスを生成するときの動作を設定する
PartCreationPolicyにはCreationPolicy列挙体の値を設定します。CreationPolicyの値は以下のようなものがあります。
CreationPolicy構造体 ーー Shared : 全体で共有する。つまりシングルトン。 ーー NonShared : 共有しない。つまり毎回インスタンスを作る。 ーー Any : Sharedを求められるならSharedでNonSharedを求められるならNonSharedにもなる柔軟な感じ
例:NonSharedに設定された場合、インスタンスは違うものになる。
// Export属性を使ってカタログに収集してもらう対象にする
[Export]
// インスタンスを共有しないようにする
[PartCreationPolicy(CreationPolicy.NonShared)]
public class A
{
// このプロパティの型に一致するクラスのインスタンスを
// コンテナ内から探してセットしてという意味
[Import]
public B Value { get; set; }
// Bクラスを使って処理をする
public void Foo()
{
this.Value.Bar();
}
}
Aクラスのインスタンス同士の比較とAクラスが参照しているBクラスのインスタンス同士を比較しています。
// 現在実行中のアセンブリからカタログを作成する
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
// 現在実行中のアセンブリのカタログを元にコンテナを作る
var container = new CompositionContainer(catalog);
// Aクラスのインスタンスを2つ取得する
var typeA1 = container.GetExportedValue<A>();
var typeA2 = container.GetExportedValue<A>();
// typeA1とtypeA2を比較してみると・・・
Console.WriteLine("typeA1 == typeA2 -> {0}", typeA1 == typeA2);
// ついでにAクラスが参照しているBクラスが同一なのか確認
Console.WriteLine("typeA1.Value == typeA2.Value -> {0}", typeA1.Value == typeA2.Value);
実行すると、以下のような結果になります。
typeA1 == typeA2 -> False
typeA1.Value == typeA2.Value -> True
MEF的基础知识
代码实例:
class Program2
{
//导入对象使用
[Import("chinese_hello")] ////////////
public Person oPerson { set; get; }
////////这里的chinese_hello是和Export里面的chinese_hello对应的,由此可知,每一个
[Import("chinese_hello")]这种Import一定可以找到一个对应的Export,如果找不到,程序就会报异
常。当然如果这里的Import如果改成[Import("american_hello")],那么oPerson肯定就对应一个
American对象。
上面的[Import("chinese_hello")]等价于Person oPerson=new Chinese();。看到这里可能有人就会说
这个Import是多此一举了,既然我们可以new,为什么非要用这种奇怪的语法呢,怪别扭的。其实
如果我们站在架构的层面,它的好处就是可以减少dll之间的引用。
//////////
static void Main(string[] args)
{
var oProgram = new Program2();
oProgram.MyComposePart();
var strRes = oProgram.oPerson.SayHello("李磊");
Console.WriteLine(strRes);
Console.Read();
}
//宿主MEF并组合部件///////////
void MyComposePart()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
//将部件(part)和宿主程序添加到组合容器
container.ComposeParts(this);
//////////////添加到组合容器中之后,如果该类里面有Import,MEF才会自动去寻找对应的Export。
这也就是为什么使用MEF前必须要组合部件的原因。
//////////////////
}
}
public interface Person
{
string SayHello(string name);
}
//声明对象可以导出
[Export("chinese_hello", typeof(Person))]//////////
public class Chinese : Person
{
public string SayHello(string name)
{
return "你好:" + name ;
}
}
[Export("american_hello", typeof(Person))]
public class American : Person
{
public string SayHello(string name)
{
return "Hello:" + name ;
}
}
通过上面的例子我们可以知道,对象是可以通过Import和Export来实现导入和导出的。 同理,对象的属性、字段、方法、事件等也可以通过[Import/Export]进行导入和导出。 想要一次导入多个对象:[ImportMany]。注意:使用ImportMany的时候对应的Export不能有chinese_hello这类string参数。直接使用 [Export(typeof(Person))]
class Program2
{
[ImportMany]
public IEnumerable<Person> lstPerson { set; get; }
static void Main(string[] args)
{
var oProgram = new Program2();
oProgram.MyComposePart();
Console.WriteLine(oProgram.lstPerson.Count());
Console.Read();
}
void MyComposePart()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
//将部件(part)和宿主程序添加到组合容器
container.ComposeParts(this);
}
}
public interface Person
{
string SayHello(string name);
}
[Export(typeof(Person))]
public class Chinese : Person
{
public string SayHello(string name)
{
return "你好:" + name ;
}
}
[Export(typeof(Person))]
public class American : Person
{
public string SayHello(string name)
{
return "Hello:" + name ;
}
}
输出结果为2
从下面的例子可以看到:oPerson对象已经实例化了,而oPerson2.Value对象没有实例化,当程序执行var strRes2 = oProgram.oPerson2.Value.SayHello("Lilei")这一句的时候,oPerson2.Value对象才进行实例化。这种需要在某些对程序性能有特殊要求的情况下面有一定的作用。
部分代码略
[Import("chinese_hello")]
public Person oPerson { set; get; }
[Import("american_hello")]
public Lazy<Person> oPerson2 { set; get; }
static void Main(string[] args)
{
var oProgram = new Program2();
oProgram.MyComposePart();
var strRes = oProgram.oPerson.SayHello("李磊");
var strRes2 = oProgram.oPerson2.Value.SayHello("Lilei");
Console.WriteLine(strRes);
Console.Read();
}
MEF应用例子 http://www.cnblogs.com/landeanfen/p/4760740.html
初期化処理ーーIPartImportsSatisfiedNotificationインターフェース http://blog.okazuki.jp/entry/20110425/1303740414 https://code.msdn.microsoft.com/Managed-Extensibility-3332350b IPartImportsSatisfiedNotificationインターフェース:パーツのインポートが満たされたときに、そのパーツに通知します。 OnImportsSatisfiedメソッド:MEFのコンテナ内で初期化が終わったタイミングで呼び出されます。
namespace MEFInitSample
{
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
// コンテナ初期化
var c = new CompositionContainer(
new AssemblyCatalog(Assembly.GetExecutingAssembly()));
// IPartImportsSatisfiedNotification.OnImportsSatisfiedの動作確認
Console.WriteLine("PersonClient取得前");
var client = c.GetExportedValue<PersonClient>();
Console.WriteLine("PersonClient取得後");
}
}
[Export]
public class PersonClient : IPartImportsSatisfiedNotification
{
[Import]
public Person Person { get; set; }
public PersonClient()
{
Console.WriteLine("PersonClient.ctor() called");
Console.WriteLine(" this.Person = " + this.Person);
}
public void OnImportsSatisfied()
{
// ここでは、Personクラスの設定が完了しているので好きなように使える
Console.WriteLine("PersonClient.OnImportsSatisfied() called");
Console.WriteLine(" this.Person = " + this.Person);
}
}
[Export]
public class Person
{
}
}
先ほど説明したIPartImportsSatisfiedNotificationをPersonClientに実装しています。OnImportsSatistfiedでPersonプロパティの値を表示しています。これを実行すると、以下の結果が表示されます。
PersonClient取得前
PersonClient.ctor() called
this.Person =
PersonClient.OnImportsSatisfied() called
this.Person = MEFInitSample.Person
PersonClient取得後
最初のthis.Personの出力は、まだ値が設定されていないので何も表示されていません。そして、OnImportsSatisfiedではインスタンスが設定されているので、きちんと表示されています。
遅延初期化のLazy http://blog.okazuki.jp/entry/20110305/1298432049 ー延期初期化の必要 大規模なアプリケーションには、数百以上のプラグインから構成されることも珍しくありません。これらのプラグインが全て起動時に初期化されると、パフォーマンス影響が必至である。
このような問題を回避するために、とりあえず不要なものは初期化しないというアプローチがよくとられます。起動時には必要最低限の初期化処理だけやって、必要になったタイミングでプラグインのインスタンスを生成するという感じです。
ー やりかた Importする側をLazyにする LazyのValueプロパティにアクセスしたタイミングでインスタンスが作られる
// 遅延初期化の場合
[Export]
class LazyApplication
{
[ImportMany]
public IEnumerable<Lazy<IPlugin>> Plugins { get; set; }
public void Run()
{
foreach (var plugin in this.Plugins)
{
// ここで初めてクラスのインスタンスが作成される
plugin.Value.Execute();
}
}
}
面向接口编程
关于GetExportedValue的使用示例
// 挨拶屋
interface IGreeter
{
void Greet();
}
// IGreeterとしてTnakaクラスをExport
[Export(typeof(IGreeter))]
class Tanaka : IGreeter
{
public void Greet()
{
Console.WriteLine("こんにちは!たなかです!");
}
}
static void Main(string[] args)
{
// コンテナを作るところはお馴染み
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
// Tanakaさんをくださいな
var g = container.GetExportedValue<IGreeter>();
// 挨拶実行
g.Greet();
}
この状態でプログラムを実行すると、以下のような結果になります。
こんにちは!たなかです!
如果把[Export(typeof(IGreeter))]换成[Export],
interface IGreeter
{
void Greet();
}
// まずは普通にExport
[Export]
class Tanaka : IGreeter
{
public void Greet()
{
Console.WriteLine("こんにちは!たなかです!");
}
}
那么,下面代码会报错
var g = container.GetExportedValue<IGreeter>();
// 挨拶実行
g.Greet();
但是,下面代码会成功
var g = container.GetExportedValue<Tanaka>();
// 挨拶実行
g.Greet();
同じ型で複数個Export
// IGreeterとしてTnakaクラスをExport
[Export("Tanaka", typeof(IGreeter))] //Export时,类名也要声明
class Tanaka : IGreeter
{
public void Greet()
{
Console.WriteLine("こんにちは!たなかです!");
}
}
// IGreeterとしてOkazukiクラスをExport
[Export("Okazuki", typeof(IGreeter))]
class Okazuki : IGreeter
{
public void Greet()
{
Console.WriteLine("犬のアイコンです");
}
}
static void Main(string[] args)
{
// コンテナを作るところはお馴染み
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
// Tanakaさんをくださいな
var t = container.GetExportedValue<IGreeter>("Tanaka");
// 挨拶実行
t.Greet();
// Okazukiさんをくださいな
var o = container.GetExportedValue<IGreeter>("Okazuki");
// 挨拶実行
o.Greet();
}
结果:
こんにちは!たなかです!
犬のアイコンです
CompositionContainer.GetExports 取出多个exports对象
GetExports
Import
[Export(typeof(IAction))]
public class MyAction : IAction
{
public void DoAction() {
Console.WriteLine("My Action Invoked");
}
}
public class ActionManager
{
[Import(typeof(IAction))]
private IAction _action;
}
这便是最最基本的导入和导出,我们都约定了IAction作为契约,所以这样的导入导出可以得到匹配。
ImportMany
複数のクラスをImportする専用のImportManyという属性になります。
ImportManyはIEnumerable
[Export]
class GreeterClient
{
// IGreeterとしてExportされているものを全てかき集める
[ImportMany]
public IEnumerable<IGreeter> Greeters { get; set; }
// 全員に挨拶させる
public void Execute()
{
foreach (var g in this.Greeters)
{
g.Greet();
}
}
}
このGreeterClientはIGreeter型としてExportされているものを全てImportして、Executeメソッドで全員に挨拶をさせるクラスです。
[ImportMany] public IEnumerable<Lazy<IMyPlugin, IMyExportAttribute>> xxxxx 的时候
《IMyPlugin.cs》
public interface IMyPlugin
{
void Execute();
}
《IMyExportAttribute.cs》
public interface IMyExportAttribute
{
string ExtensionName { get; } //< 拡張機能の名称
}
《MyExportAttribute.cs》
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class MyExportAttribute: ExportAttribute, IMyExportAttribute
{
public MyExportAttribute(string extensionName)
: base(typeof(IMyPlugin))
{
this.ExtensionName = extensionName;
}
public string ExtensionName { get; private set; }
}
《MyPluginA.cs》
[MyExport("MyPluginA")] //注意使用的是MyExport
public class MyPluginA : IMyPlugin
{
public MyPluginA()
{
Console.WriteLine("PluginAのコンストラクタ");
}
public void Execute()
{
Console.WriteLine("PluginAのExecute");
}
}
《MyPluginB.cs》
[MyExport("MyPluginB")] //注意使用的是MyExport
class MyPluginB : IMyPlugin
{
public MyPluginB()
{
Console.WriteLine("PluginBのコンストラクタ");
}
public void Execute()
{
Console.WriteLine("PluginBのExecute");
}
}
《Client.cs》
[Export]
class Client
{
[ImportMany]
public IEnumerable<Lazy<IMyPlugin, IMyExportAttribute>> Plugins { get; set; }
public void Run()
{
foreach (var ex in this.Plugins)
{
Console.WriteLine($"[{ex.Metadata.ExtensionName}] ");
ex.Value.Execute();
}
}
}
《Program.cs》
class Program
{
static void Main(string[] args)
{
Console.WriteLine("アプリケーションを開始します。");
if (!Directory.Exists("Extensions"))
Directory.CreateDirectory("Extensions");
var assm = new AssemblyCatalog(Assembly.GetExecutingAssembly()); // "Application"アセンブリ内にある拡張機能を読み込む
var extensions = new DirectoryCatalog("Extensions"); // "Extensions"フォルダ内にある拡張機能(DLLファイル)を読み込む
var agg = new AggregateCatalog(assm, extensions); // 2つのカタログをマージしたカタログを作成する
var container = new CompositionContainer(agg);
var app = container.GetExportedValue<Client>();
app.Run();
Console.WriteLine("アプリケーションを終了します。");
Console.ReadLine();
}
}
执行结果:
アプリケーションを開始します。
[MyPluginA]
PluginAのコンストラクタ
PluginAのExecute
[MyPluginB]
PluginBのコンストラクタ
PluginBのExecute
アプリケーションを終了します。
ImportingConstructor https://docs.microsoft.com/en-us/dotnet/framework/mef/attributed-programming-model-overview-mef By default, when creating a part, the composition engine uses the parameter-less constructor. To make the engine use a different constructor, you can mark it with the ImportingConstructor attribute.
[Export(typeof(IPowerManagerDomainService))]
public class PowerManagerDomainService:IPowerManagerDomainService
{
private IUserRepository _userRepository = null;
private IRoleRepository _roleRepository = null;
private IUserRoleRepository _userroleRepository = null;
[ImportingConstructor]
public PowerManagerDomainService(IUserRoleRepository oUserRoleRepository)
//IUserRoleRepository 声明了[Export(typeof(IUserRepository))]
{
_userroleRepository = oUserRoleRepository;
}
}
如果某一个接口(IUserRepository)存在多个实现类(UserRepository_A和UserRepository_B)的导出, 则可以写为:
[ImportingConstructor]
public PowerManagerDomainService([Import("userRepository_A", typeof(IUserRepository))]IUserRepository oUserRepository, IRoleRepository oRoleRepository)
{
_userRepository = oUserRepository;
_roleRepository = oRoleRepository;
}
注意: 确保该类型具有默认构造函数或有一个标记有“System.ComponentModel.Composition.ImportingConstructorAttribute”的构造函数。 MEF的ImportingConstructorAttribute特性不支持这种多个构造函数同时标注的情况。
中文讲解: http://www.cnblogs.com/landeanfen/p/4848885.html
PartCreationPolicy:MEF部件的生命周期 CreationPolicy.Any:表示可共享或不共享,部件的实例用MEF容器根据不同的请求需求自动控制。 CreationPolicy.Shared表示共享部件,既Shared类型的插件部件可以在多个MEF组合容器中共用,而且多次请求该部件返回的其实是同一个对象。 CreationPolicy.NonShared类型,表示不共享部件实例,每当有新的请求就会创建一个新的对象实例。
如果再系统中需要关闭某个界面,再重新打开时需要新创建一个实例的就不能忘记设置PartCreationPolicy为CreationPolicy.NonShared。
[Export("ViewB", typeof(IView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class ViewB : UserControl,IView
{
public ViewB()
{
InitializeComponent();
}
}
IPartImportsSatisfiedNotification Notifies a part when its imports have been satisfied. public interface IPartImportsSatisfiedNotification
成员函数: OnImportsSatisfied():Called when a part's imports have been satisfied and it is safe to use.
MEFから設定されるインスタンスが設定されたあとに初期か処理を行いたいときはIPartImportsSatisfiedNotificationを実装するということ。
namespace MEFInitSample
{
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
// コンテナ初期化
var c = new CompositionContainer(
new AssemblyCatalog(Assembly.GetExecutingAssembly()));
// IPartImportsSatisfiedNotification.OnImportsSatisfiedの動作確認
Console.WriteLine("PersonClient取得前");
var client = c.GetExportedValue<PersonClient>();
Console.WriteLine("PersonClient取得後");
}
}
[Export]
public class PersonClient : IPartImportsSatisfiedNotification
{
[Import]
public Person Person { get; set; }
public PersonClient()
{
Console.WriteLine("PersonClient.ctor() called");
Console.WriteLine(" this.Person = " + this.Person);
}
public void OnImportsSatisfied()
{
// ここでは、Personクラスの設定が完了しているので好きなように使える
Console.WriteLine("PersonClient.OnImportsSatisfied() called");
Console.WriteLine(" this.Person = " + this.Person);
}
}
[Export]
public class Person
{
}
}
MEF plugin的初始化 经过Demo确认,plugin在被加载时会自动被调用constructor函数从而实现初始化; 如果plugin有多个constructor函数, 则优先选择[ImportConstrustor]属性的constructor函数(当然,其参数对应的类必须要相应的声明Export)。 如果不存在[ImportConstrustor]属性,则选择无参数的constructor函数。 发现plugin实例在被container load后就被初始化了(默认用无参数的constructor函数)。 如果constructor函数有参数,并需要import, 则必须声明importingConstruct.
自己写代码确认:
<IPlugin.cs>
public interface IPlugin
{
void Execute();
}
<Plugin1.cs>
[Export(typeof(IPlugin))]
public class Plugin1 : IPlugin
{
private ObjectA objA { get; set; }
public Plugin1()
{
Console.WriteLine("Plugin1 Contructor.");
}
[ImportingConstructor] //不声明这个的话,会抱错。
public Plugin1(ObjectA a)
{
objA = a;
Console.WriteLine("Plugin1 with objA Contructor.");
}
void IPlugin.Execute()
{
Console.WriteLine("Plugin1 exected.");
}
}
[Export]
public class ObjectA
{
private ObjectA()
{
Console.WriteLine("ObjectA Constructor.");
}
}
<Program.cs>
class Program
{
[Import]
private IPlugin plugin { get; set; }
static void Main(string[] args)
{
var oProgram = new Program();
Console.WriteLine("Begin");
oProgram.LoadPlugin();
oProgram.plugin.Execute();
Console.ReadKey();
}
private void LoadPlugin()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this); //此时plugin实例的construct函数被调用。
Console.WriteLine("LoadPlugin finish.");
}
}
MEF plugin的初始化 经过Demo确认,plugin在被加载时会自动被调用constructor函数从而实现初始化; 如果plugin有多个constructor函数, 则优先选择[ImportConstrustor]属性的constructor函数(当然,其参数对应的类必须要相应的声明Export)。 如果不存在[ImportConstrustor]属性,则选择无参数的constructor函数。 发现plugin实例在被container load后就被初始化了(默认用无参数的constructor函数)。 如果constructor函数有参数,并需要import, 则必须声明importingConstruct.
自己写代码确认:
<IPlugin.cs>
public interface IPlugin
{
void Execute();
}
<Plugin1.cs>
[Export(typeof(IPlugin))]
public class Plugin1 : IPlugin
{
private ObjectA objA { get; set; }
public Plugin1()
{
Console.WriteLine("Plugin1 Contructor.");
}
[ImportingConstructor] //不声明这个的话,会抱错。
public Plugin1(ObjectA a)
{
objA = a;
Console.WriteLine("Plugin1 with objA Contructor.");
}
void IPlugin.Execute()
{
Console.WriteLine("Plugin1 exected.");
}
}
[Export]
public class ObjectA
{
private ObjectA()
{
Console.WriteLine("ObjectA Constructor.");
}
}
<Program.cs>
class Program
{
[Import]
private IPlugin plugin { get; set; }
static void Main(string[] args)
{
var oProgram = new Program();
Console.WriteLine("Begin");
oProgram.LoadPlugin();
oProgram.plugin.Execute();
Console.ReadKey();
}
private void LoadPlugin()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
Console.WriteLine("new container finish.");
container.ComposeParts(this); //此时plugin实例的construct函数被调用。
Console.WriteLine("container.ComposeParts(this) finish.");
}
}
输出结果:
Begin
new container finish.
ObjectA constructor.
Plugin1 with objA Constructor.
container.ComposePart(this ) finished.
Plugin1 exected.
メタデータ
// Labelという名前であいさつマシーンというデータをつけてる
[Export]
[ExportMetadata("Label", "あいさつマシーン")]
public class Greeter
{
public void Execute()
{
Console.WriteLine("こんにちは");
}
}
// publicじゃないとダメ
public interface IGreeterMetadataView
{
// メタデータと同じ名前、型の読み取り専用プロパティを定義する
string Label { get; }
}
.....
// 現在のアセンブリからコンテナを作る
var c = new CompositionContainer(
new AssemblyCatalog(Assembly.GetExecutingAssembly()));
// GetExportで取得する型とメタデータの型を定義する
Lazy<Greeter, IGreeterMetadataView> g = c.GetExport<Greeter, IGreeterMetadataView>();
// LazyのMetadataプロパティでメタデータを取得できる
Console.WriteLine(g.Metadata.Label);
// もちろんGreeterの処理も実行できる
g.Value.Execute();
// 挨拶インターフェース
interface IGreeter
{
void Execute();
}
// メタデータのインターフェース
public interface IGreeterMetadataView
{
string Label { get; }
}
// IGreeterでExportして追加でラベルというメタデータを指定するカスタム属性
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
class GreetreExportAttribute : ExportAttribute, IGreeterMetadataView
{
public GreetreExportAttribute(string label)
: base(typeof(IGreeter))
{
this.Label = label;
}
public string Label { get; private set; }
}
// 適当に3つほどIGreeterを実装してGreeterExport属性をつけておく
[GreetreExport("日本人")]
class JapaneseGreeter : IGreeter
{
public void Execute()
{
Console.WriteLine("こんにちは");
}
}
[GreetreExport("割と普通")]
class NormalianGreeter : IGreeter
{
public void Execute()
{
Console.WriteLine("エロース、エロース");
}
}
[GreetreExport("アメリカ人")]
class EnglishGreeter : IGreeter
{
public void Execute()
{
Console.WriteLine("Hello.");
}
}
..........
[Export]
class Client
{
// 複数受け取る
[ImportMany]
public IEnumerable<Lazy<IGreeter, IGreeterMetadataView>> Greeters { get; set; }
public void Run()
{
foreach (var g in this.Greeters)
{
// メタデータを表示してから挨拶をしてもらう
Console.Write(g.Metadata.Label + " : ");
g.Value.Execute();
}
}
}
結果:
日本人 : こんにちは
割と普通 : エロース、エロース
アメリカ人 : Hello.
MEF作为IOC的方式之一,它的主要作用是解耦,MEF加上面向接口编程,可以使得你的设计更加灵活。