Как установить ExportMetaData с несколькими значениями, а также с одним настраиваемым атрибутом? - PullRequest
13 голосов
/ 10 января 2011

В моем классе установлены следующие атрибуты ExportMetaData:

  [Export(typeof(IDocumentViewer))]
  [ExportMetadata("Name", "MyViewer")]
  [ExportMetadata("SupportsEditing", true)]
  [ExportMetadata("Formats", DocFormat.DOC, IsMultiple = true)]
  [ExportMetadata("Formats", DocFormat.DOCX, IsMultiple = true)]
  [ExportMetadata("Formats", DocFormat.RTF, IsMultiple = true)]  

У меня также есть интерфейс поддержки:

  public interface IDocumentViewerMetaData {
    /// <summary>
    /// Gets the format.
    /// </summary>
    /// <value>The format.</value>
    IEnumerable<DocFormat> Formats { get; }
    /// <summary>
    /// Gets the name of the viewer
    /// </summary>
    /// <value>The name.</value>
    string Name { get; }
    /// <summary>
    /// Gets a value indicating whether this viewer supports editing
    /// </summary>
    /// <value><c>true</c> if [supports editing]; otherwise, <c>false</c>.</value>
    bool SupportsEditing { get; }
  }

И, конечно, мой ImportMany:

[ImportMany(typeof(IDocumentViewer))]
public IEnumerable<Lazy<IDocumentViewer, IDocumentViewerMetaData>> _viewers { get; set; }

То, что я хотел бы сделать, это использовать строго типизированный класс атрибута вместо использования атрибута ExportMetaData. Я не нашел способ сделать это, также поддерживая отдельные значения (Name, SupportsEditing, в приведенном выше примере).

Я предполагаю сделать что-то похожее на следующее (или то, что предложено как лучшее):

[Export(typeof(IDocumentViewer))]
[DocumentViewerMetadata(Name = "MyViewer")]
[DocumentViewerMetadata(SupportsEditing = true)]
[DocumentViewerMetadata(Format = DocFormat.DOC)]
[DocumentViewerMetadata(Format = DocFormat.DOCX)]

Я вполне уверен, что есть способ сделать это, я просто не нашел правильный способ соединить точки. :)

1 Ответ

18 голосов
/ 11 января 2011

Вы можете создать подкласс ExportAttribute в своей собственной реализации и украсить его MetadataAttribute, чтобы позволить MEF использовать его свойства для проецирования прокси метаданных, который он использует во время композиции:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property),
 MetadataAttribute]
public class ExportDocumentViewerAttribute : ExportAttribute, IDocumentViewerMetadata
{
  public ExportDocumentViewer(string name, bool supportsEditing, params DocFormat[] formats)
    : base(typeof(IDocumentViewer))
  {
    if (string.IsNullOrEmpty(name))
      throw new ArgumentException("Export requires a name", "name");

    Name = name;
    SupportsEditing = supportsEditing;
    Formats = formats ?? Enumerable.Empty<DocFormat>();
  }

  public string Name { get; private set; }

  public bool SupportsEditing { get; private set; }

  public IEnumerable<DocFormat> Formats { get; private set; }
}

[ExportDocumentViewer("Word", true, DocFormat.DOC, DocFormat.DOCX)]
public WordDocumentViewer : IDocumentViewer
{
  // Stuff
}

Примечание на самом деле вам не нужно украшать его вашим IDocumentViewerMetadata контрактом, поскольку MEF будет проецировать его независимо, я просто предпочитаю, чтобы я знал, внесу ли я изменения в контракт метаданных, что мой пользовательский экспортатрибут соответствует.

...