En lenguaje C # y .NET framework, ¿podría ayudarme a comprender a los delegados? Estaba tratando de verificar algún código y descubrí que los resultados que recibí fueron inesperados para mí. Aquí está:
class Program
{
public static int I = 0;
static Func<string> del = new Func<string>(I.ToString);
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del());
}
}
La respuesta fue 0, pero no 10. ¿Por qué?

()invocaríaToString.Funcs, fue una suposición :)staticmétodo. Cuando representa un método de instancia, el delegado contiene tanto el objeto "objetivo" en el que invocar el método como la información del método. Entonces, cuando digadel = I.ToString;,delmantendrá el objetoIque aquí es unInt32(tipo de valor inmutable). Cuando usa una función anónimadel = () => I.ToString();, el compilador crea un métodostatic string xxx() { return I.ToString(); }y eldelobjeto contiene ese método generado.Respuestas:
La razón es la siguiente:
La forma en que declara el delegado apunta directamente al
ToStringmétodo de la instancia int estática. Se captura en el momento de la creación.Como señala flindeberg en los comentarios a continuación, cada delegado tiene un objetivo y un método para ejecutar en el objetivo.
En este caso, el método a ejecutar es obviamente el
ToStringmétodo. La parte interesante es la instancia en la que se ejecuta el método: es la instancia deIen el momento de la creación, lo que significa que el delegado no está usandoIpara que la instancia se use, sino que almacena la referencia a la instancia en sí.Más tarde, cambia
Ia un valor diferente, básicamente asignándole una nueva instancia. Esto no cambia mágicamente la instancia capturada en su delegado, ¿por qué debería hacerlo?Para obtener el resultado que espera, deberá cambiar el delegado a esto:
static Func<string> del = new Func<string>(() => I.ToString());Así, el delegado apunta a un método anónimo que se ejecuta
ToStringen la corrienteIen el momento de la ejecución del delegado.En este caso, el método a ejecutar es un método anónimo creado en la clase en la que se declara el delegado. La instancia es nula ya que es un método estático.
Eche un vistazo al código que genera el compilador para la segunda versión del delegado:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0); private static string cctor>b__0() { return UserQuery.I.ToString(); }Como puede ver, es un método normal que hace algo . En nuestro caso, devuelve el resultado de llamar
ToStringa la instancia actual deI.fuente
Debe pasar
Ia su función para queI.ToString()pueda ejecutarse en el momento adecuado (en lugar de en el momento en que se crea la función).class Program { public static int I = 0; static Func<int, string> del = num => num.ToString(); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del(I)); } }fuente
Así es como se debe hacer esto:
using System; namespace ConsoleApplication1 { class Program { public static int I = 0; static Func<string> del = new Func<string>(() => { return I.ToString(); }); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del()); } } }fuente
El delegado de C # permite encapsular tanto un objeto como una instancia y un método. Una declaración de delegado define una clase que se deriva de la clase System.Delegate. Una instancia delegada encapsula una lista de invocaciones, que es una lista de uno o más métodos, cada uno de los cuales se denomina entidad invocable.
aprender más formulario
http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html
fuente
Supongo que los valores int se pasan por valores, no por referencias, y por esa razón al crear el delegado, es un delegado al método ToString del valor actual de "I" (0).
fuente
Foolugar deinty cambiara la líneaI = 10aI = new Foo(10), tendría exactamente el mismo resultado que con el código actual.I.Value = 10es algo completamente diferente. Esto no asigna una nueva instancia aI. Pero asignar una nueva instancia aIes el punto importante aquí.