Exports 선언
MEF 는 Export 를 통해 외부로 구성요소를 노출할 수 있습니다. Export 는 System.ComponentModel.Composition.ExportAttribute 특성을 통해 선언합니다. 이 특성은 클래스 뿐만 아니라 프로퍼티와 메서드에도 선언을 할 수 있습니다.
구성요소 Export 하기
ExportAttribute 특성을 사용하여 아래와 같이 구성요소를 외부로 노출하게 됩니다. ExportAttribute 은 몇 가지의 시그너처(Signature) 를 제공하는데 매개변수를 생략하게 될 경우 MEF 은 클래스의 타입으로 Contract 를 매핑하게 됩니다.
[Export] class MessageSender { } |
프로퍼티 Export
프로퍼티를 Export 하는 방법입니다. 프로퍼티를 Export 할 수 있게 되어 여러 가지 면에서 유리할 수 있습니다.
Core CLR 이 제공하는 타입(Type) 뿐만 아니라 외부의 다양한 타입(Type) 을 사용할 수 있습니다. 프로퍼티에 Export 를 선언할 수 있음으로써 Export 를 구조적으로 분리하여 단순화 할 수 있습니다. 그러므로 같은 구성요소 내에서 Export 간의 Related 관계를 가질 수 있습니다.
아래의 코드와 같이 Timeout 프로퍼티는 Contract 를 맺게 됩니다.
public class Configuration { [Export("Timeout")] public int Timeout { get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); } } } [Export] public class UsesTimeout { [Import("Timeout")] public int Timeout { get; set; } } |
메서드 Export
구성요소의 메서드를 Export 할 수 있습니다. 메서드의 Export 는 기본적으로 대리자(Delegate) 를 통해 호출하게 됩니다. 메서드를 Export 하게되면 보다 더 세세한 제어를 가능하게 하고, 심플하게 방법으로 Code Generating 이 가능합니다.
public class MessageSender { [Export(typeof(Action<string>))] public void Say(string message) { Console.WriteLine(message); } } [Export] public class MessageProcess { [Import(typeof(Action<string>))] public Action<string> MessageSender { get; set; } public void Send() { MessageSender("Call send process in MessageProcess"); } } |
그리고 ExportAttribute 은 타입(Type) 대신 문자열을 사용하여 Contract 를 사용할 수 있습니다.
public class MessageSender { [Export("MessageSender")] public void Say(string message) { Console.WriteLine(message); } } [Export] public class MessageProcess { [Import("MessageSender")] public Action<string> MessageSender { get; set; } public void Send() { MessageSender("Call send process in MessageProcess"); } } |
아래의 소스 코드는 이번 예제에서 사용된 전체 소스 코드입니다.
namespace ExportSample { class Program { [Import] MessageProcess MessageProcess { get; set; } [STAThread] static void Main(string[] args) { Program p = new Program(); p.Run(); p.MessageProcess.Send(); } private void Run() { var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly())); var container = new CompositionContainer(catalog); var batch = new CompositionBatch(); batch.AddPart(this); container.Compose(batch); } } public class MessageSender { [Export("MessageSender")] public void Say(string message) { Console.WriteLine(message); } } [Export] public class MessageProcess { [Import("MessageSender")] public Action<string> MessageSender { get; set; } public void Send() { MessageSender("Call send process in MessageProcess"); } } } |
Export 요약
이렇게 ExportAttribute 을 사용하여 Contract 를 제공하는 것은 굉장히 중요한 의미를 가지게 됩니다. 플러그인 모델(Plugin Model) 에서 Export 는 구성요소를 외부로 노출하는, 즉 Contract 의 방법을 제공해 주게 됩니다.

Contract 맺음으로써 개발자는 Contract Base 로 단지 Contract 만 제공받으면 됩니다. 이러한 Contract 는 제한된 상호작용을 극복하여 대부분의 커플링(Coupling)을 해소할 수 있으며, 플로그인 모델(Plugin Model) 에서 보다 쉽게 구성요소를 캡슐화 할 수 있습니다.