Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Определение собственных областей видимости в MEF

Anna | 18.06.2014 | нет комментариев
Managed Extensibility Framework aka MEF, что бы не говорили любители навороченных Autofac-ов и прочих StructureMap-ов, является простым и наглядным методом организации композиции в приложении. И позже объемной дискусии с уважаемым Razaz по поводу крепких и слабых сторон MEF хотелось бы продемонстрировать вероятности определения собственных областей видимости в этом контейнере.


Областей видимости в MEF, как вестимо, каждого две — Shared (один экземпляр на каждый контейнер) и NonShared (новейший экземпляр на всякий запрос экспорта). Вероятно, один из первых вопросов тех, кто постигает данный контейнер позже Unity: «А где же видимость per-thread?». Либо, для разработчиков WCF-служб, «per-call».
Не вдаваясь в вопрос, для чего это необходимо в рамках задач композиции, испробую показать несложный пример реализации этих политик видимости в всеобщем виде.Для тех, кому не хочется читать об этапах создания и технических деталях, здесь дозволено пощупать руками код, а здесь — забрать в виде пакета.

Работает только в MEF 2.0, а отчего — ниже.

Выходит.
Испробуем для начала поставить задачу в всеобщем виде:
«В рамках запроса экспорта есть определенный контекст. В момент этого запроса требуется отдавать один и тот же экземпляр экспорта для одного и того же контекста, и различные экземпляры — для различных контекстов.»

Не знаю как вы, а я сразу увидел в этом обыкновенный словарь «ключ-значение», где ключ — и есть наш контекст. Разумеется, словарь должен быть один на каждый контейнер, следственно Shared, но это мы зададим позднее.

    public abstract class AffinityStorage<TExport, TAffinity> where TExport : class
    {        
        private ConcurrentDictionary<TAffinity,TExport> _partStorage
            = new ConcurrentDictionary<TAffinity,TExport>();

        internal TExport GetOrAdd(TAffinity affinity, Func<TExport> creator)
        {
            var t = _partStorage.GetOrAdd(affinity, (a) =>creator());          
            return t;
        }

        internal void RemoveAffinity(TAffinity affinity)
        {
            TExport val;
           _partStorage.TryRemove(affinity, out val);
        }
    }

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

Но где взять данный фабричный способ? Помним, что он должен воротить полновесную часть, допустимо, со своими собственными импортами.
Для этого воспользуемся вероятностью MEF возвращать экземпляр части в «ленивом» виде. А для определения контекста да и вообще в качестве обертки сделаем еще один класс — политику приобретения. Она в перспективе NonShared, т.к. наш ленивый экспорт должен быть при всяком запросе новейший (а создавать его либо нет — разберется наше хранилище).

    public abstract class Policy<TExport, TAffinity>  where TExport : class
    {

        private readonly AffinityStorage<TExport, TAffinity> _storage;

        [Import(AllowRecomposition = true, RequiredCreationPolicy = CreationPolicy.NonShared)]
        private Lazy<TExport> _lazyPart;

        private bool _wasCreated;       
        private int _wasDisposed;

        protected abstract TAffinity GetAffinity();

        protected Policy(AffinityStorage<TExport, TAffinity> storage)
        {
            _storage = storage;
        }

        private TExport GetExportedValue()
        {
            _wasCreated = true;
            return _storage.GetOrAdd(GetAffinity(), () => _lazyPart.Value);
        }        

        protected void DestroyAffinity(TAffinity affinity)
        {
            var wasDisposed = Interlocked.CompareExchange(ref _wasDisposed, 1, 0);
            if (_wasCreated && wasDisposed == 0)
            {
                _storage.RemoveAffinity(affinity);              
            } 
        }

       public static implicit operator TExport(Policy<TExport, TAffinity> threadPolicy)
        {
            return threadPolicy.GetExportedValue();
        }                 
    }

Тут, как видим, присутствуют:

  • наш фабричный способ в виде Lazy&ltTExport&gt, непременно NonShared, напротив для чего он необходим
  • неявное реформирование политики в целевой тип через приобретение экспорта в нашем хранилище
  • собственно определение того, что же есть контекст, в виде абстрактного способа, тот, что мы будем реализовыв

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB