Контракты в MEF

86

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

Для калькулятора используются те же самые контракты, которые были определены ранее: ICalculator иIOperation.

Еще одним контрактом является IcalculatorExtension. Этот интерфейс определяет свойства Title и Description, которые могут быть использованы приложением-хостом. Метод GetUI() возвращает FrameworkElement, который позволяет дополнению вернуть любой элемент WPF, унаследованный от FrameworkElement, который должен быть показан в качестве пользовательского интерфейса внутри хоста:

using System.Windows;

namespace MEF
{
    public interface ICalculatorExtension
    {
        string Title { get; }
        string Description { get; }

        FrameworkElement GetUI();
    }
}

Интерфейсы .NET обеспечивают хороший контракт между приложением-хостом и дополнением. Если интерфейс определен в отдельной сборке, как в случае со сборкой CalculatorContract, то приложение-хост и дополнения не имеют прямой зависимости.

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

[Export("MEF.SampleContract")]
public class Foo
{
   public string Bar()
   {
      return "Foo.Bar";
   }
}

Проблема с применением контракта как строки, состоит в том, что методы, свойства и события, предоставляемые типом, не являются строго типизированными. Либо вызывающий код должен ссылаться на тип Foo, чтобы использовать его, либо для доступа к его членам должна применяться рефлексия .NET. Ключевое слово C# 4 dynamic облегчает использование рефлексии и может существенно помочь в подобных сценариях.

Приложение-хост может применять тип dynamic для импорта контракта по имени MEF.SampleContract:

[Import("MEF.SampleContract")]
public dynamic Foo { get; set; }

Благодаря ключевому слову dynamic, свойство Foo может применяться для прямого доступа к методу Вar(). Вызов этого метода разрешается во время выполнения:

string s = Foo.Bar();

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

Пройди тесты
Лучший чат для C# программистов