티스토리 뷰
Exports and Metadata
Export 에 Metadata 를 등록하고 제어하는 방법입니다. 지난 포스트에서 알 수 있듯이 Export 는 구성 요소간에 Contact 를 제공하여 이들을 구성(Composition) 할 수 있는 플러그인 모델(Plugin Model) 을 제공해 줍니다.
하지만 Contract 가 제공되어 구성 요소를 확장하고 구성하는 것은 매우 용이하다는 것을 알게 되었으나 Contract 로 인해 파생된 다양한 구성 요소를 어떻게 제어하느냐의 고민을 하게 됩니다. 즉, 다양한 구성 요소 가운데 내가 필요로 하는 구성 요소를 골라낼 수 있도록 Metadata 를 제공하여 구성 요소를 질의(Query)할 수 있도록 하는 것입니다.
예를 들어 아래와 같은 Export 구성 요소 중 어떻게 EmailMessageSender 로 Say() 를 호출할 것인가가 문제인 것이죠.
[Export(typeof(IMessageSender))]
public class EmailMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import EmailMessageSender");
}
}
[Export(typeof(IMessageSender))]
public class PhoneMessageSneder : IMessageSender
{
public void Say()
{
Console.WriteLine("Import PhoneMessageSneder");
}
}
[Export(typeof(IMessageSender))]
public class SmsMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import SmsMessageSender");
}
} |
이런 경우, 원초적인 방법으로 리플랙션(Reflection) 을 이용하여 Type 검사를 통해 EmailMessageSender 를 골라내서 사용하면 되지만, 직접적으로 Type 을 검사하기 위해서는 Tightly Coupling 이 발생하여 결국 유연한 플러그인 모델을 구현하기 위해 아무런 도움이 되지 않습니다.
이러한 방법을 해소하기 위해 또 다른 우회 방법은 리플랙션을 통해 Modules Name 으로 비교하는 방법이지만, 이것 또한 플러그인 모델에서 구성 요소가 교체 되었을 경우를 생각하면 전혀 대응할 수 없는 방법입니다.
MEF 에서는 이런 문제를 해소하기 위해 Contract 에 Metadata 를 제공하며 정적/동적인 방법을 제공해 줍니다.
Attaching Metadata to an Export
Export 에 Metadata 를 제공해 주기 위해서 MEF 에서는 ExportMetadataAttribute 특성을 제공해 줍니다.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field,
AllowMultiple = true, Inherited = false)]
public ExportMetadataAttribute(string name, object value)
왜 ExportMetadata 클래스는 sealed 로 선언이 되었나요?
일반적으로 sealed 로 클래스를 봉인할 경우 리플랙션의 성능이 향상됩니다.
|
ExportMetadata 는 키와 값(Key/Value) 을 지정하여 Contract 에 Metadata 를 제공해 줄 수 있습니다. 그리고 하나의 Export 에 여러 개의 Metadata 를 제공할 수 있도록 AllowMultiple 을 지원합니다.
Metadata 는 여러 가지의 정보를 포함할 수 있습니다. Export 가 제공하는 기능의 특성을 기술할 수 있으며, 예를 들어, 권한, 로깅, 구성 요소 분류 방법 등이 될 수 있을 것입니다.
아래의 소스 코드는 Metadata 를 지정하는 예를 보여줍니다.
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Email")]
[ExportMetadata("Logging", true)]
public class EmailMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import EmailMessageSender");
}
}
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Phone")]
public class PhoneMessageSneder : IMessageSender
{
public void Say()
{
Console.WriteLine("Import PhoneMessageSneder");
}
}
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Sms")]
public class SmsMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import SmsMessageSender");
}
}
|
Constraining Imports statically
MEF Preview 5 에서는 ImportRequiredMetadataAttribute 클래스가 제거되었습니다.
MEF Preview 4 에서는 선언적인 방법으로 ImportRequiredMetadataAttribute 를 통해 Metadata 를 질의할 수 있었으나, MEF Preview 5 에서는 ImportRequiredMetadataAttribute 클래스가 제거되었습니다.
아마도 추측으로는 ImportRequiredMetadataAttribute 를 선언 시에 여러 개의 구성 요소가 검색될 경우 Exception 이 발생하는데, Exception 을 최소화 하고자 제거가 된 것 같습니다.
혹시 Statically 한 방법으로 ImportRequiredMetadataAttribute 에 대응되는 클래스를 아시면 저에게 알려주세요. |
Constraining Imports dynamically
이 방법은 Export 의 ExportMetadata 를 런타임 시에 질의(Query) 하는 방법입니다.
Import 시 ExportCollection<T> 을 사용하여 Export 를 수동적으로 질의(Query) 하는 방법입니다. 이 방법은 지난 포스트의 Lazy Load 를 이용한 방법으로 단지 Metadata 만 질의(Query) 뿐이고, 객체의 생성에 대한 판단은 필요 시에만 GetExportedobject() 메서드를 이용하여 생성할 수 있습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MetadataSample
{
class Program
{
[Import(typeof(IMessageSender))]
ExportCollection<IMessageSender> Sender { get; set; }
static void Main(string[] args)
{
Program program = new Program();
program.Run();
foreach (var export in program.Sender)
{
if ((string)export.Metadata["SenderType"] == "Email")
export.GetExportedObject().Say();
if (export.Metadata.ContainsKey("Logging") &&
(bool)export.Metadata["Logging"] == true)
Console.WriteLine("Logged success");
}
}
void Run()
{
var catalog = new AggregateCatalog(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))]
[ExportMetadata("SenderType", "Email")]
[ExportMetadata("Logging", true)]
public class EmailMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import EmailMessageSender");
}
}
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Phone")]
public class PhoneMessageSneder : IMessageSender
{
public void Say()
{
Console.WriteLine("Import PhoneMessageSneder");
}
}
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Sms")]
public class SmsMessageSender : IMessageSender
{
public void Say()
{
Console.WriteLine("Import SmsMessageSender");
}
}
}
}
|
실행 결과는 예상할 수 있듯이 아래와 같이 런타임 시에 결과를 보여줍니다.
'.NET > .NET Framework' 카테고리의 다른 글
[MEF] 9. Recomposition (2) | 2009.04.20 |
---|---|
[MEF] 8. Strongly Typed Metadata (0) | 2009.04.17 |
[MEF] 6. Lazy Exports (0) | 2009.04.13 |
MEF Preview 5 Released (0) | 2009.04.09 |
[MEF] 4. Import 선언 (6) | 2009.04.07 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- 2,841,419
- Today
- 40
- Yesterday
- 71
링크
- ***** MY SOCIAL *****
- [SOCIAL] 페이스북
- [SOCIAL] 팀 블로그 트위터
- .
- ***** MY OPEN SOURCE *****
- [GITHUB] POWERUMC
- .
- ***** MY PUBLISH *****
- [MSDN] e-Book 백서
- .
- ***** MY TOOLS *****
- [VSX] VSGesture for VS2005,200…
- [VSX] VSGesture for VS2010,201…
- [VSX] Comment Helper for VS200…
- [VSX] VSExplorer for VS2005,20…
- [VSX] VSCmd for VS2005,2008
- .
- ***** MY FAVORITES *****
- MSDN 포럼
- MSDN 라이브러리
- Mono Project
- STEN
- 일본 ATMARKIT
- C++ 빌더 포럼
- .
TAG
- 땡초
- TFS 2010
- Team Foundation Server 2010
- ASP.NET
- umc
- 비주얼 스튜디오 2010
- c#
- Windows 8
- .NET
- Visual Studio 2010
- Visual Studio 11
- testing
- Team Foundation Server
- 비주얼 스튜디오
- monodevelop
- TFS
- Managed Extensibility Framework
- Silverlight
- github
- test
- 엄준일
- LINQ
- POWERUMC
- Visual Studio 2008
- 팀 파운데이션 서버
- mono
- MEF
- Visual Studio
- .NET Framework 4.0
- ALM
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
글 보관함
- 2020/05 (1)
- 2019/10 (3)
- 2018/11 (1)
- 2018/08 (2)
- 2017/04 (1)
- 2017/01 (2)
- 2016/11 (2)
- 2016/08 (1)
- 2016/05 (1)
- 2016/04 (2)
- 2016/02 (2)
- 2016/01 (1)
- 2015/05 (1)
- 2015/04 (2)
- 2015/03 (1)
- 2015/02 (1)
- 2015/01 (1)
- 2014/11 (1)
- 2014/09 (2)
- 2014/08 (2)
- 2014/05 (2)
- 2014/04 (3)
- 2014/03 (2)
- 2014/02 (2)
- 2014/01 (4)
- 2013/12 (2)
- 2013/11 (1)
- 2013/10 (2)
- 2013/09 (6)
- 2013/08 (3)