Managed Extensibility Framework - Documentationの 第三回です。Declaring Exports を見ていきます。
ExportAttribute Class (System.ComponentModel.Composition) は、プロパティやメソッドにも付与出来るのですが、それのサンプルコードが載っています。
メソッドについては、MEF Programming Guide 1.Hosting MEF in an application を試してみた - お だ のスペース で試したので省略。
プロパティについては、こんな感じです。
using System; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; public class Program { public static void Main(string[] args) { Program p = new Program(); p.Run(); Console.ReadKey(); } public void Run() { var i = new UsesTimeout(); Compose(i); Console.WriteLine(i.Timeout); Console.ReadKey(); } private void Compose(UsesTimeout i) { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this, i); } } public class Configuration { [Export("Timeout")] public int Timeout { get { return 10; } } } public class UsesTimeout { [Import("Timeout")] public int Timeout { get; set; } }
これで、Run メソッド内の Console.WriteLine(i.Timeout); で 10 が表示されます。ちなみにどういう動きをするのか気になってプロパティに対して set してみると色々見えてきた。
using System; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; public class Program { public static void Main(string[] args) { Program p = new Program(); p.Run(); Console.ReadKey(); } public void Run() { var i = new UsesTimeout(); Compose(i); Console.WriteLine(i._timeout); // 10 Console.WriteLine(i.Timeout); // 10 i.Timeout = 2; // set してみる。 Console.WriteLine(i._timeout); // 2 Console.WriteLine(i.Timeout); // 2 Console.ReadKey(); } private void Compose(UsesTimeout i) { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); Console.WriteLine(i._timeout); // 0 container.ComposeParts(this, i); Console.WriteLine(i._timeout); // 10 } } public class Configuration { [Export("Timeout")] public int Timeout { get { return 10; } } } public class UsesTimeout { public int _timeout; [Import("Timeout")] public int Timeout { get { return _timeout; } set { _timeout = value; } } }
このコードを実行してみると、ComposeParts した際に、Export属性が付いているプロパティから値を取得し、Import属性が付いているプロパティに値を設定しているみたい。
プロパティの実装が置き換わるのでは無く、単に値だけ設定しているってことみたい。これは、以下のようにコードを書き換えても動くことからわかる。
public class UsesTimeout { [Import("Timeout")] public int _timeout; // [Import("Timeout")] public int Timeout { get { return _timeout; } set { _timeout = value; } } }
ちなみに、Non Public な物も指定可能と書いてある。
using System; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; public class Program { public static void Main(string[] args) { Program p = new Program(); p.Run(); Console.ReadKey(); } public void Run() { var i = new UsesTimeout(); Compose(i); i.Test(); Console.ReadKey(); } private void Compose(UsesTimeout i) { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this, i); } } public class Configuration { [Export("Timeout")] private int Timeout { get { return 10; } } } public class UsesTimeout { [Import("Timeout")] private int Timeout { get; set; } public void Test() { Console.WriteLine(Timeout); } }
但し、
MEF supports discovery of public and non-public Parts. You don't need to do anything to enable this behavior. Please note that in medium/partial trust environments (including Silverlight) non-public composition will not be supported.
Silverlight等の部分信頼な環境ではサポートしていませんって書いてるのかな?今度、Silverlight でも試してみる。