Strongly Typed Metadata
지난 포스트의 [MEF] 7. Exports and Metadata를 통해 Export 의 Contract 에 Metadata 를 제공하는 방법을 알아보았습니다.
MetadataAttribute 을 선언하여 Export 의 Metadata 를 제공하는 방법입니다.
[Export(typeof(IMessageSender))] [ExportMetadata("SenderType", "Email")] [ExportMetadata("Logging", true)] public class EmailMessageSender : IMessageSender { public void Say() { Console.WriteLine("Import EmailMessageSender"); } } |
Export 에 Metadata 를 제공해 주어서 무척 고맙지만, 위의 방법처럼 MetadataAttribute 를 선언하는 방법을 사용하기에 그다지 내키지 않는 구석이 있습니다.
아무래도 아래와 같은 이유 때문이겠죠?
l 메타데이터의 타입 불안정
l 빌드 시 오류를 해결이 어려움
l 사용상 모든 키값을 외우기 어렵고, 오타 발생 위험
위의 이유 때문에 Metadata 를 사용하기 위해 강력한 타입을 원하게 될 것입니다. 그리고 강력한 타입의 Metadata 를 사용하길 권장 드립니다.
Declaring Strongly Typed Metadata
Attribute 을 상속받아 Export 의 Metadata 를 Strongly Typed 으로 확장시키는 방법입니다.
아래의 Stringly Typed Metadata 를 위해 Attribute 클래스를 만드는 소스 코드 입니다.
[MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] public class MessageSenderTypeAttribute : Attribute { public MessageSenderTransport Transport { get; set; } public bool IsSecure { get; set; } public MessageSenderTypeAttribute() { } public MessageSenderTypeAttribute(MessageSenderTransport transport) : this(transport, false) { } public MessageSenderTypeAttribute(MessageSenderTransport transport, bool isSecure) { this.Transport = transport; this.IsSecure = IsSecure; } } public enum MessageSenderTransport { Email, Phone, Sms } |
Strongly Typed Metadata 를 위한 Attribute 클래스를 완성하였으면, 이것을 그대로 ExportAttribute 과 함께 추가적으로 선언하면 됩니다.
그리고 ExportAttribute 을 선언한 코드에 위의 Attribute 특성을 부여합니다. 아래는 그 소스 코드의 일부입니다.
[Export(typeof(IMessageSender))] [MessageSenderType(MessageSenderTransport.Email)] public class EmailMessageSender : IMessageSender { public void Say() { Console.WriteLine("Import EmailMessageSender"); } } [Export(typeof(IMessageSender))] [MessageSenderType(MessageSenderTransport.Phone, true)] public class PhoneMessageSneder : IMessageSender { public void Say() { Console.WriteLine("Import PhoneMessageSneder"); } } [Export(typeof(IMessageSender))] [MessageSenderType(Transport=MessageSenderTransport.Sms, IsSecure=true)] public class SmsMessageSender : IMessageSender { public void Say() { Console.WriteLine("Import SmsMessageSender"); } } |
그렇다면 아래와 같이 Metadata 를 Strongly Typed 으로 질의(Query) 할 수 있게 됩니다.
아래의 소스 코드는 지난 포스트의 소스 전체 소스 코드를 참고하십시오.
foreach (var export in program.Sender) { if ((MessageSenderTransport)export.Metadata["Transport"] == MessageSenderTransport.Sms) { export.GetExportedObject().Say(); if ((bool)export.Metadata["IsSecure"] == true) { Console.WriteLine("Security message"); } } } |
위의 소스 코드 실행 결과는 원하던 결과대로 다음과 같습니다.

[그림1] Strongly Typed 질의 결과
하지만 아직도 문제는 남아 있는 것 같아 보이네요. Strongly Typed 으로 Export Metadata 를 선언하였지만 여전히 질의(Query) 과정은 똑같은 문제점을 가지고 있습니다.
l 메타데이터의 질의(Query) 과정의 타입 불안정
l 빌드 시 오류를 해결이 어려움
l 사용상 모든 키값을 외우기 어렵고, 오타 발생 위험
More Strongly Typed Metadata Query
Metadata 를 질의(Query) 하기 위해 MEF 는 보다 강력하게 Import 하는 방법을 제공해 줍니다. 확장된 MetadataAttribute 에 인터페이스(Interface) 를 구현하도록 하여 Import 시에 인터페이스(Interface) 를 통한 Metadata 를 질의(Query) 하는 방법입니다.
우선 Attribute 에 사용되는 프로퍼티를 인터페이스로 선언합니다.
public interface IMessageSenderTypeAttribute { bool IsSecure { get; } MessageSenderTransport Transport { get; } } |
단, 여기에서 반드시 Getter 만 선언하셔야 합니다. Setter 를 선언하시면 MEF 는 Setter 프로퍼티로 인해 유효하지 않는 Attribute 으로 인식하여 예외를 발생하게 됩니다.
아래의 소스 코드는 Metadata Attribute 클래스에 위의 인터페이스를 구현한 코드 입니다.
[MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] public class MessageSenderTypeAttribute : Attribute, IMessageSenderTypeAttribute { public MessageSenderTransport Transport { get; set; } public bool IsSecure { get; set; } public MessageSenderTypeAttribute() { } public MessageSenderTypeAttribute(MessageSenderTransport transport) : this(transport, false) { } public MessageSenderTypeAttribute(MessageSenderTransport transport, bool isSecure) { this.Transport = transport; this.IsSecure = IsSecure; } } |
이제 Export 의 MetadataView 로 질의할 수 있도록 MetadataView 의 인터페이스를 알려주도록 해야 합니다.
[Import(typeof(IMessageSender))]
ExportCollection<IMessageSender, IMessageSenderTypeAttribute> Sender { get; set; }
아래의 소스 코드는 MetadataView 를 통해 Strongly Typed 으로 Export Metadata 를 질의(Query) 하는 소스 코드 입니다.
[Import(typeof(IMessageSender))] ExportCollection<IMessageSender, IMessageSenderTypeAttribute> Sender { get; set; } static void Main(string[] args) { Program program = new Program(); program.Run(); foreach (var export in program.Sender) { if (export.MetadataView.Transport == MessageSenderTransport.Email) { export.GetExportedObject().Say(); } } } |