Это хороший способ реализации модели асинхронного программирования? - PullRequest
5 голосов
/ 07 февраля 2010

В последнее время я плакал, пытаясь узнать все, что я могу о .Net Multithreading. (Становлюсь лучше, но все равно чувствую, что есть чему поучиться). Прямо сейчас я сосредотачиваюсь на APM (Модель асинхронного программирования), которая обычно известна как это:

//non async method
public int DoSomeWork(int arg)
{
   //do something and return result
}

//async version
public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
{

}

public int EndDoSomeWork(IAsyncResult result)
{

}

Теперь, допустим, я пишу какую-то библиотеку, и я хочу показать эту функциональность любому, кто использует мой API, я думал о способах реализации этого шаблона. Реализация интерфейса IAsyncResult возможна, но кажется довольно сложной. Мой вопрос, если использование делегата является приемлемым решением. Что я имею в виду под этим:

public class MyClass
{
    private Func<int, int> func;

    //non async method
    public int DoSomeWork(int arg)
    {
        //do something and return result
    }

    //async version
    public IAsyncResult BeginDoSomeWork(int arg, AsyncCallback callback, object @object)
    {
        this.func = new Func<int, int>(DoSomeWork);
        var asyncResult = this.func.BeginInvoke(arg,callback,object);
        return asyncResult;
    }

    public int EndDoSomeWork(IAsyncResult result)
    {
        return this.func.EndInvoke(result);
    }
}

По сути, каждый делегат имеет встроенные функции BeginXxx и EndXxx. Можно ли воспользоваться этим и просто раскрыть IAsyncResult или что-то не так с этим, о чем я не думаю.

Ответы [ 5 ]

1 голос
/ 07 февраля 2010

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

Почему бы вам просто не экстернализовать использование делегата?

Я имею в виду, что если вы просто поместите реальную логику в свой класс, но затем пусть каждый, кто вызывает ваш метод, сделает:

MyClass c = new MyClass();
Func<int, int> f = c.DoSomeWork;
IAsyncResult ar1 = f.BeginInvoke(1, null, null);
IAsyncResult ar2 = f.BeginInvoke(2, null, null);
//...

Я думаю, что я защищаюдаже не внедряя APM самостоятельно, а просто рекомендуя людям, вызывающим ваш метод, использовать APM, встроенный в делегаты.

0 голосов
/ 08 февраля 2010

Лично я предпочитаю использовать событие для уведомления о завершении асинхронного процесса, если класс предназначен для использования другой библиотекой, с использованием класса AsyncOperation и делегата SendOrPostCallback, чтобы убедиться, что события в потоке вызывающих объектов возникают, чтобы не прерыватьпользовательский интерфейс.Однако если асинхронная операция должна выполняться в той же сборке, я предпочитаю, чтобы вызывающий код определял, как сделать асинхронный вызов.

0 голосов
/ 07 февраля 2010

Я думаю, что это очень правильное упражнение, если ничего больше. Я тоже работаю над асинхронным обработчиком «делегата». Вы можете повысить гибкость и многое узнаете об асинхронной модели.

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

Вот пример моего старого кода по публикации асинхронных методов. Это датированное упражнение по обучению рефлексии и некоторые интересные реализации. Примите это за то, что оно стоит, но это может помочь вам с некоторыми идеями:

public delegate void delVoidMethod(params object[] args);

/// <summary>
/// Publishes an asynchronous method to the delegate collection.
/// </summary>
/// <param name="methodOwner">Target object owning the delegated method.</param>
/// <param name="method">The delegated method.</param>
/// <param name="callback">The method designated as a callback delegate.</param>
/// <param name="ptr">The delegated method's runtime handle.</param>
/// <returns>True if publishing was successful.</returns>
public bool PublishAsyncMethod(object target , MethodInfo method ,
    MethodInfo callback , out IntPtr ptr)
{
    try
    {
        ptr = method.MethodHandle.Value;

        delVoidMethod dMethod = (delVoidMethod)Delegate.CreateDelegate
            (typeof(delVoidMethod) , target , method);
        AsyncCallback callBack = (AsyncCallback)Delegate.CreateDelegate
             (typeof(AsyncCallback) , target , callback);

        handlers[ptr] = new DelegateStruct(dMethod , callBack);

        Logger.WriteLine("Delegate : {0}.{1} -> {2}.{3} published." ,
            method.DeclaringType.Name , method.Name ,
            callback.DeclaringType.Name , callback.Name);
        return true;
    }
    catch (ArgumentException ArgEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            ArgEx.Source , ArgEx.InnerException , ArgEx.Message);
    }
    catch (MissingMethodException BadMethEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            BadMethEx.Source , BadMethEx.InnerException , BadMethEx.Message);
    }
    catch (MethodAccessException MethAccEx)
    {
        Logger.Write(DH_ERROR , ERR_MSG ,
            MethAccEx.Source , MethAccEx.InnerException , MethAccEx.Message);
    }

    ptr = IntPtr.Zero;

    return false;
}
0 голосов
/ 07 февраля 2010

Абсолютно ничего плохого в этом нет, но это кажется немного бессмысленным.

По сути, вы реализуете шаблон фасада , но не упрощаете интерфейс. Возможно, будет лучше (в зависимости от вашей конкретной ситуации) добавить свои собственные классы, чтобы упростить использование AsyncCallback и IAsyncResult, чтобы вызовы более точно отражали свойства, используемые в ваших классах.

0 голосов
/ 07 февраля 2010

ИМХО, я не думаю, что ваш асинхронный метод добавляет какое-либо значение, поэтому просто позвольте клиенту решить, будет ли он вызывать ваш метод асинхронно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...