Могу я создание объекта управления с помощью MEF?

Примите асинхронную природу javascript!

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

Методы, которые я здесь описал, предназначены для разных случаев использования и примерно упорядочены по сложности.

Различаются следующие вещи:

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

    Это довольно базовая реализация, предполагающая, что условие в какой-то момент станет истинным. С помощью нескольких настроек его можно расширить, чтобы сделать его еще более полезным (например, путем установки ограничения вызовов). (Я написал это только вчера!)

    function waitFor(predicate, successCallback) {
        setTimeout(function () {
            var result = predicate();
            if (result !== undefined)
                successCallback(result);
            else
                waitFor(predicate, successCallback);
        }, 100);
    }
    

    код вызова:

        beforeEach(function (done) {
            selectListField('A field');
    
            waitFor(function () {
                var availableOptions = stores.scrapeStore(optionStore);
                if (availableOptions.length !== 0)
                    return availableOptions;
            }, done);
        });
    

    Здесь я вызываю что-то, что загружает extjs 'store' и ждет, пока хранилище содержит что-то перед продолжением (beforeEach - это фреймворк для тестирования жасмина).

    Дождаться завершения нескольких вещей

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

    createWaitRunner = function (completionCallback) {
        var callback = completionCallback;
        var completionRecord = [];
        var elements = 0;
    
        function maybeFinish() {
            var done = completionRecord.every(function (element) {
                return element === true
            });
    
            if (done)
                callback();
        }
    
        return {
            getNotifier: function (func) {
                func = func || function (){};
    
                var index = elements++;
                completionRecord[index] = false;
    
                return function () {
                    func.applyTo(arguments);
                    completionRecord[index] = true;
                    maybeFinish();
                }
            }
        }
    };
    

    код вызова:

        var waiter = createWaitRunner(done);
    
        filterList.bindStore = waiter.getNotifier();
        includeGrid.reconfigure = waiter.getNotifier(function (store) {
            includeStore = store;
        });
        excludeGrid.reconfigure = waiter.getNotifier(function (store) {
            excludeStore = store;
        });
    

    Вы либо просто ждете уведомлений, либо можете также обернуть другие функции, которые используют значения, переданные функции. Когда будут вызваны все методы, будет запущен done.

    Запуск асинхронных методов по порядку

    Я использовал другой подход, когда у меня была серия асинхронных методов для вызова в строке (снова в тестах). Это в некоторой степени похоже на то, что вы можете получить в библиотеке Async - серия делает примерно то же самое, и я сначала немного прочитал эту библиотеку, чтобы посмотреть, получилось ли то, что я хотел. Я думаю, что у меня есть более приятный API для работы с тестами (+ это было интересно реализовать!).

    //provides a context for running asyncronous methods syncronously
    //the context just provides a way of sharing bits of state
    //use run to execute the methods.  These should be methods that take a callback and optionally the context as arguments
    //note the callback is provided first so you have the option of just partially applying your function to the arguments you want
    //instead of having to wrap even simple functions in another function
    
    //when adding steps you can supply either just a function or a variable name and a function
    //if you supply a variable name then the output of the function (which should be passed into the callback) will be written to the context
    createSynchronisedRunner = function (doneFunction) {
        var context = {};
    
        var currentPosition = 0;
        var steps = [];
    
        //this is the loop. it is triggered again when each method finishes
        var runNext = function () {
            var step = steps[currentPosition];
            step.func.call(null,
                           function (output) {
                               step.outputHandler(output);
                               currentPosition++;
    
                               if (currentPosition === steps.length)
                                   return;
    
                               runNext();
                           }, context);
        };
    
        var api = {};
    
        api.addStep = function (firstArg, secondArg) {
            var assignOutput;
            var func;
    
            //overloads
            if (secondArg === undefined) {
                assignOutput = function () {
                };
                func = firstArg;
            }
            else {
                var propertyName = firstArg;
                assignOutput = function (output) {
                    context[propertyName] = output;
                };
                func = secondArg;
            }
    
            steps.push({
                           func: func,
                           outputHandler: assignOutput
                       });
        };
    
        api.run = function (completedAllCallback) {
            completedAllCallback = completedAllCallback || function(){};
    
            var lastStep = steps[steps.length - 1];
            var currentHandler = lastStep.outputHandler;
            lastStep.outputHandler = function (output) {
                currentHandler(output);
                completedAllCallback(context);
                doneFunction();
            };
    
            runNext();
        };
    
        //this is to support more flexible use where you use a done function in a different scope to initialisation
        //eg the done of a test but create in a beforeEach
        api.setDoneCallback = function (done) {
            doneFunction = done;
        };
    
        return api;
    };
    

    код вызова:

    beforeAll(function (done) {
        var runner = createSynchronisedRunner(done);
        runner.addStep('attachmentInformation', testEventService.getAttachmentCalled.partiallyApplyTo('cat eating lots of memory.jpg'));
        runner.addStep('attachment', getAttachment.partiallyApplyTo("cat eating lots of memory.jpg"));
        runner.addStep('noAttachment', getAttachment.partiallyApplyTo("somethingElse.jpg"));
        runner.run(function (context) {
            attachment = context.attachment;
            noAttachment = context.noAttachment;
        });
    });
    

    PartiallyApplyTo здесь в основном переименованная версия реализации Curry Дуга Крокфорда. Многое из того, с чем я работаю, принимает в качестве последнего аргумента обратный вызов, поэтому простые вызовы можно выполнять, как это, вместо того, чтобы оборачивать все с помощью дополнительной функции.

    Надеюсь, некоторые идеи там могут быть полезны для людей.

5
задан Chris Charabaruk 18 August 2011 в 07:08
поделиться

3 ответа

В настоящее время нет прямого способа сделать это в MEF, но команда MEF рассматривает возможность поддержки этого в v.Next. По сути, вы хотите создать несколько экземпляров одной и той же реализации, что традиционно делается с использованием шаблона Factory. Итак, один из подходов, который вы могли бы использовать, выглядит примерно так:

public interface IRandomNumberGeneratorFactory
{
  IRandomNumberGenerator CreateGenerator(int seed);
}

[Export(typeof(IRandomNumberGeneratorFactory))]
public class ConcreateRNGFactory : IRandomNumberGeneratorFactory
{
  public IRandomNumberGenerator CreateGenerator(int seed)
  {
    return new ConcreateRNG(seed);
  }
}

public class Consumer
{
  [Import(typeof(IRandomNumberGeneratorFactory))]
  private IRandomNumberGeneratorFactory generatorFactory;
  private List<IRandomNumberGenerator> generators;    
  private List<double> seeds;    

  public Consumer()    
  {
    generators = new List<IRandomNumberGenerator>();
    seeds = new List<double>(new[] {1.0, 2.0, 3.0});

    foreach(var seed in seeds)
    {            
      generators.Add(generatorFactory.CreateGenerator(seed));
    }
  }
}
5
ответ дан 14 December 2019 в 01:15
поделиться

Я считаю, что для этого и предназначена функция Ленивый экспорт . На этой странице:

[Import]
public Export<IMessageSender> Sender { get; set; }

В этом случае вы соглашаетесь отложить создание этого экземпляра до тех пор, пока вам действительно не понадобится экземпляр реализации. Для запроса экземпляра используйте метод [Export.GetExportedObject ()]. Обратите внимание, что этот метод никогда не будет действовать как фабрика реализаций T, поэтому при его многократном вызове будет возвращен один и тот же экземпляр объекта, возвращенный при первом вызове.

0
ответ дан 14 December 2019 в 01:15
поделиться

Предварительный просмотр MEF 8 имеет экспериментальную поддержку, хотя еще не включен в System.ComponentModel.Composel.dll . Смотрите этот пост в блоге для получения более подробной информации.

Вам нужно будет скачать исходники MEF и собрать решение. В папке Samples\DynamicInstantiation находится сборка Microsoft.ComponentModel.Composition.DynamicInstantiation.dll. Добавьте ссылку на эту сборку и добавьте провайдер динамической инстанцирования в свой контейнер следующим образом:

var catalog = new DirectoryCatalog(".");
var dynamicInstantiationProvider  = new DynamicInstantiationProvider();
var container = new CompositionContainer(catalog, dynamicInstantiationProvider);
dynamicInstantiationProvider.SourceProvider = container;

Теперь ваши части смогут импортировать PartCreator, если им нужно динамически создавать Foo части. Преимуществом по сравнению с написанием собственного заводского класса является то, что это прозрачно позаботится об импорте Foo, и импорте и т.д..

редактирование :

  • в MEF Preview 9 PartCreator было переименовано в ExportFactory, но оно включено только в серебряное издание.
  • в MEF 2 Preview 2, ExportFactory включено в настольное издание. Так что ExportFactory, вероятно, будет частью следующей версии .NET фреймворка после .NET 4.0.
4
ответ дан 14 December 2019 в 01:15
поделиться