MEF Programing Guide 3.Declaring Exports を試してみた

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 でも試してみる。