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 de Ien el momento de la creación, lo que significa que el delegado no está usando Ipara 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 corriente Ien 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 de I.