¿Dónde están documentados los métodos definidos por CLR como .BeginInvoke?

[EDITAR, completamente reformulado:] Parece que mi pregunta estaba mal redactada y mal recibida también. Así que espero que esta reformulación completa ayude …

MSDN says claramente especifica: Control.BeginInvoke () Ejecuta un delegado en el subproceso en el que se creó el identificador del control, normalmente este sería el subproceso de GUI. Y Dispatcher.BeginInvoke () se ejecutará en el subproceso donde se creó el objeto Dispatcher. Este sería cualquier hilo creado por mí.

Pero para los delegates, “el CLR define automáticamente BeginInvoke y EndInvoke” y estas llamadas se ejecutan en un ThreadPool-thread en su lugar. Además de este comportamiento diferente ligeramente sorprendente, me pregunto cómo puedo encontrar las especificaciones de todas las funciones que se implementan automáticamente.

Por ejemplo: Intelli-sense muestra que mi delegado tiene un DynamicInvoke (). Class System.Delegate {} tiene un DynamicInvoke () que puede implicar que mi delegado lo hereda. Pero Delegate {} no tiene BeginInvoke (). Y Delegate {} tiene varias funciones que mi delegado no tiene. También mi delegado obtiene un método GetObjectData (). Y esto parece provenir de ISerializable.

Entonces, en conclusión, un delegado aparece obtiene sus métodos de (1) el CLR “automáticamente”, (2) algún subconjunto de Delegate {} posiblemente MulticastDelegate {}, y posiblemente (3) ISerializble. ¿Dónde puedo encontrar una especificación completa de todos los métodos que obtiene un delegado? Especialmente interesante es BeginInvoke (), y es la firma exacta, ya que los dos métodos mencionados anteriormente con ese nombre tienen diferentes conjuntos de firmas.

[Alguien sugirió en una edición que un “delegado” es un “Delegado”. Me atrevo a decir que no.]

Gracias

Los métodos Control.Begin / End / Invoke () y Dispatcher.Begin / End / Invoke () tienen nombres idénticos y un comportamiento algo similar a los métodos Begin / End / Invoke () de un delegado, pero sin duda es mejor eliminar la idea de que son lo mismo. La diferencia más importante es que los métodos de un delegado son seguros para el tipo , algo que falta por completo en las versiones de Control y Dispatcher. El comportamiento en tiempo de ejecución es muy diferente también.

Las reglas que rigen a un delegado se detallan en la especificación CLI, ECMA 335 , capítulo II.14.6. Lo mejor es leer el capítulo, solo daré una sinopsis.

Una statement de delegado se transforma en una clase que hereda de MulticastDelegate (no Delegate como se especifica en la especificación CLI). Esa clase siempre tiene exactamente 4 miembros, su implementación en tiempo de ejecución la proporciona el CLR:

  • un constructor que toma un objeto y un IntPtr. El objeto es Delegate.Target, IntPtr es la dirección del método de destino, Delegate.Method. Estos miembros se usan más adelante cuando se invoca al delegado, la propiedad Target proporciona esta referencia si el método al que está vinculado el delegado es un método de instancia, nulo para un método estático. La propiedad Method determina qué método se invoca. No especifica estos argumentos directamente, el comstackdor los suministra cuando usa el nuevo operador o suscribe un controlador de eventos con el operador + =. Con una gran cantidad de azúcar de syntax en el caso de los eventos, no tiene que usar el nuevo operador explícitamente.

  • un método Invoke (). Los argumentos del método se generan dinámicamente y coinciden con la statement del delegado. Llamar al método Invoke () ejecuta el método de destino delegado en el mismo hilo, una llamada síncrona . Raramente lo usas en C #, solo usas el azúcar de syntax que permite invocar un objeto delegado simplemente usando el nombre del objeto, seguido de paréntesis.

  • un método BeginInvoke () proporciona una forma de realizar una llamada asincrónica . El método se completa rápidamente mientras el método de destino está ocupado ejecutando, similar a ThreadPool.QueueUserWorkItem pero con argumentos de tipo seguro. El tipo de devolución es siempre System.IAsyncResult, que se usa para averiguar cuándo se completa y se suministra la llamada asincrónica al método EndInvoke (). El primer argumento es un objeto delegado System.AsyncCallback opcional, su objective se llamará automáticamente cuando se complete la llamada asincrónica. El segundo argumento es un objeto opcional, se pasará como está a la callback, útil para realizar un seguimiento del estado. Los argumentos adicionales se generan dinámicamente y coinciden con la statement del delegado.

  • un método EndInvoke (). Se necesita un único argumento de tipo IAsyncResult, debe pasar el que obtuvo de BeginInvoke (). Completa la llamada asincrónica y libera recursos.

Cualquier método adicional que vea en un objeto delegado son los heredados de las clases base, MulticastDelegate y Delegate. Como DynamicInvoke () y GetObjectData ().

Las llamadas asincrónicas son las más complicadas y rara vez necesita usarlas. De hecho, no están disponibles en objectives .NETCore, como Silverlight. El método de destino de delegado se ejecuta en un subproceso de grupo de subprocesos arbitrario, al igual que lo hace Threadpool.QueueUserWorkItem (). Cualquier excepción no controlada que pueda arrojar se captura y finaliza el hilo, pero no su progtwig. Debe llamar a EndInvoke (), no hacerlo causará una pérdida de recursos durante 10 minutos. Si el método objective arrojó una excepción, se volverá a generar cuando llame a EndInvoke (). No tiene control sobre el hilo del grupo de subprocesos, no hay forma de cancelarlo o cancelarlo. Las clases Task o Thread son mejores alternativas.

MSDN es relevante, los métodos de un tipo de delegado no están documentados. Supone que usted sabe lo que hacen y cómo se ven desde la especificación y la statement delegada.

Según el tema de su pregunta, la respuesta sería estas líneas audaces. MSDN podría no ser mejor, pero es bueno 🙂

Jeffrey Richter ha escrito sobre lo que hizo en su pregunta anterior. Él tiene este artículo en la revista MSDN. http://msdn.microsoft.com/en-us/magazine/cc164139.aspx Este artículo le mostrará una implementación de cómo en realidad (puede que no sea en realidad, pero muy cerca de) este BeginInvoke y EndInvoke en realidad se implementa en .NET CLR. Invierta un tiempo en este artículo y después de eso, no creo que necesite leer más adelante. Jeffrey Richter también lo ha explicado muy bien en su libro CLR Via C #.

La mayoría de las aplicaciones de UI son de un solo hilo. Solo se puede acceder a los controles en la interfaz de usuario utilizando el hilo con el que se crearon.

Para lograr este Control. Invoke existe en Winforms. Invocará automáticamente su código en el hilo de la interfaz de usuario. En el mundo de WPF, no tenemos Control.Invocar. En WPF, tenemos el Dispatcher en lugar de Control.

Ahora delegue contra Delegado. Hans Passant ha proporcionado una muy buena respuesta.

Entonces, para explayarme un poco, estoy escribiendo esta respuesta.

El delegado como se menciona en MSDN es una clase. Tomemos este código (tomado de msdn http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx )

public delegate int PerformCalculation(int x, int y); 

Como puedes ver aquí, tenemos delegado (nota con una pequeña ‘d’). Esta es una palabra clave para definir un Delegado o para ponerlo en palabras simples. Esta es una palabra clave para definir una variable PerformCalculation que realmente contiene una referencia a un Método.

Creo que ya lo sabes, pero solo para completarlo.

Ahora para usar esta variable e invocar un método usando código como este:

 using System; // Declare delegate -- defines required signature: delegate void SampleDelegate(string message); class TestDelegate { private void CallMeUsingDelegate(string m_param) { Console.WriteLine("Called me using parameter - " + m_param); } public static void Main(string[] args) { // Here is the Code that uses the delegate defined above. SampleDelegate sd = new SampleDelegate(CallMeUsingDelegate); sd.Invoke("FromMain"); } } 

Ahora, para invocar un método, necesita escribir un Método completo como el método CallMeUsingDelegate anterior. C # tiene estos métodos anónimos que se pueden usar para invocar un método sin tener que escribirlo realmente como método.

Entonces, el código anterior también se puede escribir como

usando el sistema; // Declare delegate – define la firma requerida: delegate void SampleDelegate (mensaje de cadena);

 class TestDelegate { public static void Main(string[] args) { // Here is the Code that uses the delegate defined above. SampleDelegate sd = delegate(param) { Console.WriteLine("Called me using parameter - " + param); }; sd.Invoke("FromMain"); } } 

Esto hace el mismo trabajo que el código anterior. Pero ahora tenemos que escribir un código menos. El comstackdor creará un código IL idéntico para la versión anterior. Pero en el caso 2, el nuevo método tendrá un nombre autogenerado por el comstackdor.

Cuando se trata de BeginInvoke y EndInvoke, se utilizan para invocar métodos de forma asincrónica. Esto se hace usando threadpool que está disponible con el CLR.

Básicamente lo que sucede es que llamas a un método usando

 IAsyncResult ar = sd.BeginInvoke(CallMeUsingDelegate, callMeOnCompletion, sd); 

Aquí Delegate es el método que está invocando. Lo que sucederá es que el subproceso de su progtwig llamará al método BeginInvoke que invocará internamente el método especificado en el parámetro Delegate en un subproceso CLR ThreadPool. Luego, el progtwig continúa ejecutándose y devuelve un objeto que implementa la interfaz IAsyncResult. Puede usar este objeto para consultar sobre el progreso de la tarea invocada con su delegado (tenga en cuenta que el delegado sd pasó como el parámetro 3).

El método CallMeUsingDelegate se invoca en un hilo separado (de ThreadPool). Cuando la tarea se complete, ThreadPool llamará al método Callback especificado como 2 parámetro.

Viendo todo esto, ¿podría pensar, por qué necesitamos el EndInvoke, entonces?

Bueno, es porque si no llamas a EndInvoke, CLR ThreadPool mantendrá una referencia a esta operación y perderás algo de memoria. Por lo tanto, siempre es una buena práctica llamar a EndInvoke en el método de callback especificado.

Espero que esto ahora se aclare (no todos), sino algunos pensamientos.

    Intereting Posts