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
.Func
s, fue una suposición :)static
mé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;
,del
mantendrá el objetoI
que 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 eldel
objeto contiene ese método generado.Respuestas:
La razón es la siguiente:
La forma en que declara el delegado apunta directamente al
ToString
mé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
ToString
método. La parte interesante es la instancia en la que se ejecuta el método: es la instancia deI
en el momento de la creación, lo que significa que el delegado no está usandoI
para que la instancia se use, sino que almacena la referencia a la instancia en sí.Más tarde, cambia
I
a 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
ToString
en la corrienteI
en 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
ToString
a la instancia actual deI
.fuente
Debe pasar
I
a 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
Foo
lugar deint
y cambiara la líneaI = 10
aI = new Foo(10)
, tendría exactamente el mismo resultado que con el código actual.I.Value = 10
es algo completamente diferente. Esto no asigna una nueva instancia aI
. Pero asignar una nueva instancia aI
es el punto importante aquí.