Контракты в MEF
86C# и .NET --- Основы .NET --- Контракты в MEF
Следующий пример приложения расширяет предыдущий. На этот раз хост будет приложением 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();
Имена контрактов и интерфейсы также могут использоваться в сочетании для определения того, что контракт применяется только в случае совпадения имени контракта и интерфейса. Таким образом, один и тот же интерфейс можно использовать для разных контрактов.