2010-02-07 2 views
5

Я был на разрыве в последнее время, пытаясь узнать все, что я могу о .Net многопоточности. (Улучшайтесь, но все равно чувствуйте, что есть много, чтобы учиться). Сейчас я сосредоточен на APM (Asynchronous Programming Model), который широко известен как это:Является ли это хорошим способом реализации модели асинхронного программирования?

//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, или что-то не так с этим, о чем я не думаю.

ответ

1

Я думаю, что это хороший способ реализовать 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

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

+0

Это был всего лишь пример. Игнорируйте фактическую реализацию (которая, по общему признанию, выглядит глупо и бессмысленно), я прошу об использовании делегата, и это IAsyncResult. – BFree

+0

Поскольку предоставляется синхронная и асинхронная версия, клиент по-прежнему принимает такое решение. OP больше обеспокоен тем, является ли выбранный метод хорошим способом реализации APM или нет. – Crippledsmurf

+0

@BFree, теперь я. – Benny

0

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

Я знаю, что это SO question содержит некоторые упражнения 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

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

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

+0

Я не вижу сходства в том, что делает OP по сравнению с пулями, определяющими шаблон Facade. – IAbstract

0

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

Смежные вопросы