четверг, 25 июня 2009 г.

MEF

MEF – Managed Extensibility Framework – новая библиотека для создания композитных приложений. То есть приложений, которые собираются из отдельных частей.

Скачать его можно по адресу http://mef.codeplex.com/, версия на момент написания поста – Preview 5. На базе MEF построена Visual Studio 2010.

MEF по функциональности похожа на IoC-контейнеры, но авторы не стремились повторить функциональность существующих контейнеров. В MEF есть несколько уникальных фич, которых нету в  IoC-контейнерах.

Сразу примеры, снова поиск фильмов. Возьмем основной код из поста про Unity.

// Фильм
public class Movie
{
    public string Title { get; set; }
    public string Director { get; set; }
    public int Year { get; set; }
}

/// <summary>
/// Интерфейс репозитария
/// </summary>
public interface IMovieRepository
{
    IQueryable<Movie> GetMovies();
}

// Сервис поиска фильмов
[Export]
public class MovieFinder
{
    IMovieRepository _repository;

    [ImportingConstructor]
    public MovieFinder(IMovieRepository repository)
    {
        _repository = repository;
    }

    public IEnumerable<Movie> FindByTitle(string q)
    {
        return _repository
                .GetMovies()
                .Where(m => m.Title.Contains(q));
    }
}

// Заглушка для репозитария
[Export(typeof(IMovieRepository))]
public class InMemoryMovieRepository : IMovieRepository
{
    public IQueryable<Movie> GetMovies()
    {
        return new[]   
        {   
            new Movie   
            {   
                Title = "Гарри Поттер и узник Азкабана",   
                Director = "Альфонсо Куарон",   
                Year = 2004   
            },   
            new Movie   
            {   
                Title = "Звездные войны: Эпизод 2 - Атака клонов",   
                Director = "Джордж Лукас",   
                Year = 2002   
            },   
            new Movie   
            {   
                Title = "Властелин колец: Братство кольца",   
                Director = "Питер Джексон",   
                Year = 2001   
            },   
        }.AsQueryable();
    }
}  

В коде атрибутами размечены экспортируемые классы и импортирующий конструктор.

Теперь код, который это все использует.

static void Main(string[] args)
{
    //Создание каталога "частей"
    var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

    //Создание контейнера
    var container = new CompositionContainer(catalog);

    //Получение экземпляра
    var finder = container.GetExportedObject<MovieFinder>();
}

В текущем виде мало отличается от примера с Unity.

На самом деле в MEF гораздо более широкие возможности работы с импортами и экспортами. Экспортировать можно не только классы, но и методы, и значения свойств. Импортировать можно не только через конструктор, но и через свойства и даже через приватные поля (но это не будет работать в частично доверенном окружении).

Упростим пример, класс Movie и Main останутся без изменений.

[Export]
public class MovieFinder
{
    [Import]
    Func<IQueryable<Movie>> _getMovies = null;

    public IEnumerable<Movie> FindByTitle(string q)
    {
        return _getMovies().Where(m => m.Title.Contains(q));
    }
}

public class InMemoryMovieRepository
{
    [Export(typeof(Func<IQueryable<Movie>>))]
    public IQueryable<Movie> GetMovies()
    {
        return new[]   
        {   
            //...
        }.AsQueryable();
    }
}

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

Но об этом в другой раз.

3 коммент.:

Dmitry Baranov комментирует...

Физическая изоляция "отдельных частей" есть или MEF нельзя рассматривать как плагинный движок?

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

gandjustas комментирует...

Да, изоляции частей нету.
Для изоляции уже давно есть System.AddIn, но там таких возвожностей композии нет.

wisdom комментирует...

"На базе MEF построена Visual Studio 2010"

Главный MEF-dealer, Глен Блок, уточнял в интервью dotnetrocks, что не совсем "построена", а используется в нескольких местах.
А еще MEF подточен для использования в DLR, где отсутствует грань между объектом и типом.