Import 선언
 
MEF 의 구성 요소에 System.ComponentModel.Composition.ImportAttribute 특성을 선언하여 Import 를 선언할 수 있습니다. Import 는 Export 와 사용 방법이 매우 유사합니다. Import 는 프로퍼티(Properties), 필드(Fields), 생성자(Constructors) 에 선언할 수 있으며, 계약된 Export 구성 요소들을 Import 할 수 있습니다.
 
 
Property Import
 
프로퍼티로 값을 가져오기 위해 ImportAttribute 특성을 선언하면 됩니다.
 
Import 특성은 세 가지의 시그너처(Signature) 를 제공합니다.
 
public ImportAttribute();
public ImportAttribute(string contractName);
public ImportAttribute(Type contractType);
 
일반적으로 타입을 명시하지 않을 경우 프로퍼티의 타입이 Export 의 계약(Contract) 을 결정하게 됩니다.
 
아래는 프로퍼티에 Import 를 사용하는 방법입니다.
 
[Import]
MessageProcess MessageProcess { get; set; }
 
 
Field Import
 
필드의 Import 는 프로퍼티에 Import 를 선언하는 방법과 동일합니다.
 
[Import]
MessageProcess _messageProcess;
 
 
Constructor Parameters (생성자 파라메터)
 
Constructor Parameters 는 ImportingConstructor 특성을 사용하여 정의합니다. 특히 Constructor Parameters 는 여러 구성 요소를 사용하기 위해 프로퍼티 또는 필드로 선언되는 Import 의 선언을 생략할 수 있어 편리하게 사용할 수 있습니다. 또한, 암시적인 Import 가 가능하기 때문에 수동적으로 이것을 제어할 필요가 없으며, 구성 요소의 교체가 매우 용이합니다.
 
아래의 코드는 ImportingConstructor 특성을 이용하여 암시적으로 Import 하는 예입니다.
 
[Export]
public class Controller
{
   public View CurrentView { get; set; }
   public Model CurrentModel { get; set; }
 
   [ImportingConstructor]
   public Controller(View view, Model model)
   {
       this.CurrentView = view;
       this.CurrentModel = model;
   }
}
 
명시적인 Import 를 하기 위해서는 생성자 파라메터에 ImportAttribute 특성을 명시해 주면 됩니다.
 
아래는 Constructor Parameters 예의 전체 소스 코드입니다.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
 
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
 
namespace ImportSample
{
   class Program
   {
       [STAThread]
       static void Main(string[] args)
       {
             Program p = new Program();
             p.Run();
       }
      
       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);
 
             var controller = container.GetExportedObject<Controller>();
 
            
             Console.WriteLine(controller.CurrentView.ToString());
             Console.WriteLine(controller.CurrentModel.ToString());
       }
   }
 
   [Export]
   public class Controller
   {
       public View CurrentView { get; set; }
       public Model CurrentModel { get; set; }
 
       [ImportingConstructor]
       public Controller(View view, Model model)
       {
             this.CurrentView = view;
             this.CurrentModel = model;
       }
   }
 
   [Export]
   public class View
   {
       public override string ToString()
       {
             return "Export View";
       }
   }
 
   [Export]
   public class Model
   {
       public override string ToString()
       {
             return "Export Model";
       }
   }
}
 
실행 결과는
 
[그림1] Constructor Parameters 예제 소스 코드 실행 결과
 
 
Importing Collection
 
MEF 는 Composable Container 의 모든 Contract 의 인스턴스를 컬렉션으로 가져올 수 있습니다. MEF 는 플러그인 모델(Plugin Model) 로써 구성 요소를 교체와 추가/제거가 용이하다고 하였습니다. 이러한 구성 요소가 동적으로 교체 또는 컨테이너에 의해 관리가 되면서 구성 요소는 업데이트 또는 Recomposable(재구성 가능한) 될 수 있습니다.
 
Contract 기반의 MEF 구성 요소는 동적인(Dynamic)한 환경을 제공하며, 이것을 관리하기 위해 컬렉션으로 제어할 수 있습니다.
 
아래는 Importing Collection 의 예제 소스 코드입니다.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
 
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
 
namespace ImportSample
{
   class Program
   {
       [Import]
       IEnumerable<IMessageSender> MessageSenders;
 
       [STAThread]
       static void Main(string[] args)
       {
             Program p = new Program();
             p.Run();
 
             foreach (var sender in p.MessageSenders)
             {
                    sender.Say();
             }
       }
      
       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 interface IMessageSender
   {
       void Say();
   }
 
   [Export(typeof(IMessageSender))]
   public class PhoneMessageSender : IMessageSender
   {
       public void Say()
       {
             Console.WriteLine("Message Send - Phone");
       }
   }
 
   [Export(typeof(IMessageSender))]
   public class EMailMessageSender : IMessageSender
   {
       public void Say()
       {
             Console.WriteLine("Message Send - EMail");
       }
   }
}
 
IMessageSender 인터페이스를 구현한 구성 요소를 컬렉션으로 루핑하여 호출한 결과입니다.
 
[그림2] Importing Collection 예제 소스 코드 실행 결과
 
 
INotifyImportSatisfaction
 
MEF Preview 5 부터 INotifyImportSatisfaction 인터페이스는 IPartImportsSatisfiedNotification 으로 변경되었습니다.

INotifyImportSatisfaction 인터페이스는 Import 처리가 완료가 되었을 때 통보되는 인터페이스 입니다. System.ComponentModel.Composition.INotifyImportSatisfaction 인터페이스는 ImportCompleted() 메서드만 구현하면 됩니다. 클래스내 모든 Import 처리가 완료가 되었을 경우 ImportCompleted() 메서드가 호출됩니다.
 
아래 소스 코드는 INotifyImportSatisfaction 인터페이스를 구현한 예 입니다.
 
class Program : INotifyImportSatisfaction
{
 
   public void ImportCompleted()
   {
       Console.WriteLine("Completed");
   }
 
}
 
 
 
MEF 다시 보기
 
MEF 는 마치 어린 아이들이 좋아하던 조립 로봇을 보는 듯한 인상입니다. 로봇의 몸체만 있다면 팔, 다리를 끼워 로봇을 어렵지 않게 완성하는 것처럼 말입니다. 플라스틱 로봇에게 강철 옷을 입히고 싶다면, 로봇을 전부 때려부시고 새로 만들지 않고서도 MEF 를 이용하면 가능합니다. 그리고 칼과 방패를 채워주고 싶다면 그렇게 하시면 됩니다.
 
[그림3] MEF 와 조립 로봇 (그림 출처는 여기)
 
MEF 를 볼수록 하나의 작은 SOA(Service Oriented Architecture) 라고 봐도 무방할 것 같습니다. (비교하는 것이 무리이긴 하지만…) MEF 의 플러그인 모델(Plugin Model) 은 느슨한 결합(Loose Coupling) 으로 Service 와 EndPoint 의 Contract 기반의 유연한 확장성을 제공해 줍니다. 아마도 단시간내에 새로운 아키텍처의 모델로써 주목을 받을 수 있지 않을까 기대해봅니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'.NET > .NET Framework' 카테고리의 다른 글

[MEF] 6. Lazy Exports  (0) 2009.04.13
MEF Preview 5 Released  (0) 2009.04.09
[MEF] 4. Import 선언  (6) 2009.04.07
ASP.NET 에서 Entity Framework 바인딩 문제  (2) 2009.03.29
[MEF] 3. Export 선언  (0) 2009.03.29
[MEF] 2. Parts 와 Contracts 선언  (0) 2009.03.22
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 길버트 2010.01.29 11:42 신고 Address Modify/Delete Reply

    엄준일 MVP이 정리해 놓은 .NET Framework 4.0 MEF 강좌가
    Silverlight MEF 공부하기 위한 기반을 닦는데
    많이 도움이 되고 있습니다.

    감사드리구요.

    작은 질문하나 드립니다.
    Importing Collection에 인스턴스가 담기게 되는 기본순서(Default Order)는
    코드에 선언된 순서이겠지요?

    • 땡초 POWERUMC 2010.01.29 12:58 신고 Address Modify/Delete

      안녕하세요. 길벗님^_^
      먼저 Importing 순서라는 것은 존재하지 않구요.
      ComposablePartDefinition 을 통해
      Import <-> Export 관계가 성립이 됩니다.
      결국은 Export 에 따라서 Imports 가 결정이 되는데,
      그 순서는 Catalog 를 어떤것을 쓰느냐도 밀접하게 관련이 있습니다.

      아마도 굳이 순서를 매기고 싶으시면 ExportMetadata 등을 사용하시면 좋을 것 같아요.

  2. 길버트 2010.01.29 15:42 신고 Address Modify/Delete Reply

    답변 감사드려요. 제가 질문이 정확하지 못했던 것 같아서 다시 질문을 드리자면,
    [Import]를 선언한 프로퍼티 IEnumerable<IMessageSender> MessageSenders; 를 통해서
    [Export(typeof(IMessageSender))]를 선언한 IMessageSender 클래스 인스턴스들에
    접근하게 되는데요.

    이때 MessageSenders에 담기게 된 IMessageSender가 실행한 샘플 예제를 보면,
    PhoneMessageSender, EMailMessageSender 순서인 것을 확인 할 수 있습니다.
    이런 순서는 어떻게 정해진 것인지 궁금합니다. 코드 상에 선언된 순서를 바꾸면
    실행 결과도 EMailMessageSender, PhoneMessageSender 바뀌는 것인지 궁금해서
    질문을 드렸습니다.

    (한번 해보면 알텐데 저도 참 게으르네요. ^^)

    • 땡초 POWERUMC 2010.01.30 00:05 신고 Address Modify/Delete

      하하하^^
      길벗님이 귀차니즘이 있다니 놀랍네요 +_+ㅋ

      내부적으로 리플랙션으로 타입을 가져오기 때문에
      순서를 바꾸는 것을 떠나서,
      리플랙터가 타입을 가져오는 순서가 될 듯 싶습니다.

      사실 IL 코드 자체가 내부적으로 정렬 기준이 없고
      컴파일된 내부 IL 코드 순서대로 가져오기 때문에
      클래스가 파일별로 나뉘어져있고, 프로젝트가 분리되는 상황이라면
      순서는 어떻다고 제가 장담드릴 순 없을 듯 합니다요. +_+;

  3. 길버트 2010.01.31 12:24 신고 Address Modify/Delete Reply

    답변 감사드려요.
    그럼 의도하는 정렬 순서가 있을 때는
    콜렉션을 사용하기 전에 linq 등으로
    소트해서 사용하면 되겠군요.

    감사합니다.
    2010 글로벌 써밋 가십니까?

    • 땡초 POWERUMC 2010.02.01 01:21 신고 Address Modify/Delete

      저는 서밋 안가요 ^_^
      갠적인 생각으로는 PDC 재탕하는거라 ;;;

      글구 정렬 등 임의 순서를 원하시면
      LINQ 로 소트하는 것 보다는,
      ExportMetadataAttribute 을 이용해서
      Order 프로퍼티를 추가해서 사용하심이 좋을 듯 한데요.