MEF: загрузка деталей (плагинов), которые имеют разные свойства - PullRequest
2 голосов
/ 31 июля 2009

Краткое описание:

Моя команда решила использовать Microsoft Managed Extensibility Framework ( MEF ), чтобы обеспечить расширяемую модель для добавления новых "провайдеров" в нашу систему.

Это позволяет нам относительно легко подключать новых сторонних поставщиков.

Примечание: я был впечатлен тем, как просто использовать MEF и как его использовать.

Мой вопрос:

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

Какой подход следует использовать для работы с указанными плагинами провайдера из-за различных свойств? Отмечая, что все они выполняют одинаковую работу.

Мое решение:

Создайте интерфейс, которому должны соответствовать поставщики, в результате чего создается «обертка» вокруг каждого из сторонних поставщиков, что приводит к согласованному интерфейсу / модель программирования для работы с каждым провайдером.

Плагин = сторонний источник данных (поставщик) + Реализация общего интерфейса.

+ ве: Для указанных плагинов не требуется более сложный динамический «плагин» для отражения.

-ve: Нужно написать обертку для каждого провайдера. (Независимо от того, нужно ли добавлять теги MEF Export)

Примечание:

Для меня подход интерфейс / обертка был бы самым простым, но мне сказали, чтобы исследовать подход, основанный на отражении, который может использовать отражение, чтобы обнаружить свойства во время выполнения, которые могут подвергаться система.

Я не сторонник какого-либо одного решения, а другого, но мне было бы интересно услышать мысли сообщества (большинство из которых более опытны, чем я).

Спасибо.

Ответы [ 3 ]

2 голосов
/ 04 августа 2009

На самом деле в Preview 6 мы распаковали экспорт и позволили вам создать пользовательский атрибут экспорта, включающий метаданные, что устраняет необходимость для авторов детали добавлять отдельный экспорт. Все наши атрибуты импорта также распечатаны.

[MetadataAttribute]
[AttributeUsage(AllowMultiple=false)] 
public class RuleAttribute : ExportAttribute {
  public RuleAttribute(string name, string description) {
    Name=name;
    Description=description;

  } : base(typeof(IRule))

  public string Name {get;private set;}
  public string Description {get; private set;}
}

RuleAttribute выше экспортирует IRule, а также позволяет предоставлять метаданные имени.

Тогда использование будет следующим:

[Rule("AddOneRule", "Adds one to the value")]
public class AddOneRule {
}

НТН Гленн

1 голос
/ 31 июля 2009

Что я сделал для добавления такой информации, так это для того, чтобы создать некоторые пользовательские атрибуты для плагинов и затем прочитать их в MEF, когда плагины будут загружены. Вы можете добавить в класс атрибутов все, что угодно, например имена, перечисления, целые числа, другие строки, и это довольно просто в использовании. Но будьте осторожны, новый предварительный просмотр6 изменил некоторые вещи в том, как они обрабатываются.

[MetadataAttribute]
public class MyMetadataAttribute : Attribute
{
    public MyType MyUsage { get; set; }
}

public interface IMyMetadataView
{
    MyType MyUsage { get; }
}

public enum MyType
{
    Undefined,
    TypeOne,
    TypeTwo
}

И тогда в плагине вы можете определить его следующим образом ...

[Export(typeof(IMyInterface))]
[MyMetadataAttribute(MyUsage = MyType.TypeOne)]
public class PluginClass: IMyInterface
{
}

Вам нужно добавить что-то в импорт, затем также

[ImportMany(AllowRecomposition = true)]
public IEnumerable<Lazy<IMyInterface, IMyMetadataView>> plugins { get; set; }

Затем вы можете использовать данные непосредственно для каждого плагина

var typeOnePlugin = plugins.FirstOrDefault(p => p.Metadata.MyUsage == MyType.TypeOne);

Опять же, это способ предварительного просмотра 6, который вышел в июле.

1 голос
/ 31 июля 2009

Не очень понятно, о каких "свойствах" и "потоках данных" вы говорите, но все же.

Да, общий интерфейс - это всегда хорошо. И поскольку у вас есть все эти «свойства» и тому подобное, я предлагаю следующее:

interface IProperty
{
    string Name { get; }
    object Value { get; }
}

interface IDataStreamProvider
{
    Stream OpenStream();
}

interface IPlugin
{
    ReadOnlyCollection<IProperty> Properties { get; }

    ReadOnlyCollection<IDataStreamProvider> DataStreams { get; }
}

Говоря о "обертках": я не понимаю их намерений. Все сторонние плагины должны реализовывать интерфейс IPlugin и должны быть украшены либо ExportAttribute, либо PluginAttribute, как показано ниже:

class PluginAttribute : ExportAttribute
{
    public PluginAttribute() :
        base(typeof(IPlugin))
    {
    }
}

Следует избегать отражения, насколько это возможно, из-за проблем с ремонтопригодностью.

...