2010-02-07 12 views
5

He estado llorando últimamente tratando de aprender todo lo que pueda sobre .Net Multithreading. (Mejorando, pero aún siento que hay mucho que aprender). En este momento estoy centrado en el APM (Asynchronous modelo de programación) que se conoce comúnmente como esto:¿Es esta una buena manera de implementar el Modelo de programación asincrónica?

//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) 
{ 

} 

Ahora, digamos que estoy escribiendo alguna biblioteca, y quiero exponer esta funcionalidad para cualquier persona que consume mi API, estaba pensando en formas de implementar este patrón. Implementar la interfaz IAsyncResult es una posibilidad, pero parece bastante complejo. Mi pregunta es si el uso de delegado es una solución aceptable. Lo que quiero decir con esto es la siguiente:

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); 
    } 
} 

Básicamente, cada delegado tiene la funcionalidad BeginXxx y EndXxx al horno la derecha en ella. ¿Está bien aprovechar eso y solo exponer IAsyncResult, o hay algo mal con esto en el que no estoy pensando?

Respuesta

1

Creo que es una buena manera de implementar APM, pero por el momento obtendría un error con más de una llamada asincrónica por instancia.

¿Por qué no solo externalizas el uso de delegados?

Lo que quiero decir es, que si usted acaba de poner la lógica real en su clase, pero luego dejar que cualquier persona que llama a su método de hacer:

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

Creo que lo que estoy defendiendo ni siquiera la aplicación de la APM usted mismo, pero solo recomienda a las personas que llaman a su método que utilicen el APM integrado en los delegados.

0

En mi humilde opinión, no creo que su método asíncrono agregue ningún valor, así que simplemente deje que el cliente decida si llamará a su método de forma asíncrona.

+0

Fue solo un ejemplo. Ignore la implementación real (que ciertamente parece estúpida e inútil), estoy preguntando sobre el uso del delegado y es IAsyncResult. – BFree

+0

Como se proporciona una versión síncrona y asíncrona, el cliente aún puede tomar esa decisión. El OP está más preocupado acerca de si el método elegido es una buena forma de implementar APM o no. – Crippledsmurf

+0

@BFree, ahora mismo. – Benny

0

Creo que es un ejercicio muy válido por lo menos. Yo también estoy trabajando en un controlador 'delegado' asincrónico. Puede aumentar la flexibilidad y aprenderá mucho sobre el modelo asíncrono.

Sé que este SO question contiene algunos ejercicios Linq en él. Sin embargo, podría darle una idea sobre el uso de árboles de expresiones para hacerlo un poco más robusto. Todavía tengo que profundizar en el tema y proporcionarle información más concreta.

Aquí hay un ejemplo de una parte de mi código anterior sobre la publicación de métodos asíncronos. Este es un fechado en ejercicio en el aprendizaje de la reflexión y algunas implementaciones interesantes. Tomar para lo que vale, pero que podría ayudar con algunas ideas:

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

absolutamente nada malo en ello, pero parece un poco inútil.

Está implementando esencialmente el Facade pattern, pero no simplifica la interfaz. Sería mejor (dependiendo de su situación específica) agregar sus propias clases para simplificar el uso de AsyncCallback y IAsyncResult para que las llamadas reflejen con mayor precisión las propiedades utilizadas en sus clases.

+0

No veo las similitudes en lo que hace el OP en comparación con las viñetas que definen el patrón de Fachada. – IAbstract

0

Personalmente prefiero usar un evento para notificar cuando finaliza el proceso asincrónico si la clase está destinada a ser utilizada por otra biblioteca, utilizando la clase AsyncOperation y el delegado SendOrPostCallback para asegurarse de que los eventos se generan en el hilo de las personas que llaman interrumpir la interfaz de usuario. Sin embargo, si la operación asincrónica se va a ejecutar en el mismo ensamblado, prefiero que el código de llamada defina cómo realizar la llamada asincrónica.

Cuestiones relacionadas