No entiendo este caso:
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
¿Por qué la compilación está bien cuando uso el Invokemétodo y no está bien cuando regreso csharp Func<int,int>directamente?

delegate void test1(int i);ydelegate void test2(int i);Respuestas:
Hay dos cosas que necesita saber para comprender este comportamiento.
System.Delegate, pero diferentes delegados tienen diferentes tipos y, por lo tanto, no pueden asignarse entre sí.Debido a que diferentes delegados tienen diferentes tipos, eso significa que no puede asignar un delegado de un tipo a otro.
Por ejemplo, dado:
Entonces:
La primera línea anterior compila OK porque está usando el manejo especial para asignar una lambda o un método a un delegado.
De hecho, esta línea es efectivamente reescrita así por el compilador:
La segunda línea anterior no se compila porque está intentando asignar una instancia de un tipo a otro tipo incompatible.
En cuanto a los tipos, no hay una asignación compatible entre
test1ytest2porque son tipos diferentes.Si ayuda pensarlo, considere esta jerarquía de clases:
El siguiente código no se compilará, a pesar de que
Test1yTest2derivar de la misma clase base:Esto explica por qué no puede asignar un tipo de delegado a otro. Ese es solo el lenguaje normal de C #.
Sin embargo, lo crucial es entender por qué se le permite asignar un método o lambda a un delegado compatible. Como se señaló anteriormente, esto es parte del soporte de lenguaje C # para los delegados.
Así que finalmente para responder tu pregunta:
Cuando lo usa
Invoke(), está asignando una llamada de MÉTODO al delegado usando el manejo especial del lenguaje C # para asignar métodos o lambdas a un delegado en lugar de intentar asignar un tipo incompatible, por lo tanto, se compila OK.Para ser completamente claro, el código que compila en su OP:
En realidad se convierte conceptualmente en algo como:
Mientras que el código que falla intenta asignar entre dos tipos incompatibles:
fuente
En el segundo caso,
fes de tipoFunc<int, int>, pero se dice que el método devuelve atest. Estos son tipos no relacionados (delegados), que no son convertibles entre sí, por lo que se produce un error del compilador. Puede ir a esta sección de las especificaciones de idioma y buscar "delegar". No encontrará ninguna mención de conversiones entre delegados que tengan las mismas firmas.Sin embargo, en el primer caso,
f.Invokees una expresión de grupo de método , que en realidad no tiene un tipo. El compilador de C # convertirá expresiones de grupos de métodos a tipos de delegados específicos según el contexto, a través de una conversión de grupo de métodos .(Citando la quinta viñeta aquí , énfasis mío)
En este caso, se convierte al
testtipo de delegado.En otras palabras,
return fno funciona porquefya tiene un tipo, perof.Invokeaún no lo tiene.fuente
El problema aquí es la compatibilidad de tipos:
La siguiente es la definición de delegado de Func de las fuentes de MSDN:
public delegate TResult Func<in T, out TResult>(T arg);Si ve que no hay una relación directa entre el Func mencionado anteriormente y su Delegado definido:
public delegate int test(int i);Los delegados se comparan usando la firma, que es parámetros de entrada y resultado de salida, en última instancia, un delegado es un puntero de función y dos funciones se pueden comparar solo a través de la firma. En tiempo de ejecución, el método invocado a través de Func se asigna al
Testdelegado, ya que Signature es el mismo y funciona a la perfección. Es una asignación de puntero de función, dondeTestdelegado ahora invocará el método señalado por el delegado de FuncEntre Func y el delegado de prueba, no hay compatibilidad de tipo / asignación, Func no puede completar como parte de las reglas del sistema Tipo. Incluso cuando su resultado se puede asignar y completar
test delegatecomo se hizo en el primer caso.fuente