variable type multiple method generic delegate clase c# generics

c# - type - ¿Por qué es funcional<T> ambiguo con Func<IEnumerable<T>>?



generic variable c# (2)

OK, aquí está el trato.

La versión corta:

  • El error de ambigüedad es, extrañamente, correcto.
  • El compilador C # 4 también produce un error espurio después del error de ambigüedad correcto. Eso parece ser un error en el compilador.

La versión larga:

Tenemos un problema de resolución de sobrecarga. La resolución de sobrecarga está muy bien especificada.

Paso uno: determinar el conjunto de candidatos. Eso es fácil. Los candidatos son Foo(Func<IEnumerable<String>>) y Foo(Func<String>) .

Paso dos: determine qué miembros del conjunto de candidatos son aplicables . Un miembro aplicable tiene todos los argumentos convertibles a cada tipo de parámetro.

¿Es Foo(Func<IEnumerable<String>>) aplicable? Bueno, ¿es X convertible a Func<IEnumerable<String> ?

Consultamos la sección 6.6 de la especificación. Esta parte de la especificación es lo que los diseñadores de lenguaje llamamos "realmente extraño". Básicamente, dice que puede existir una conversión, pero usar esa conversión es un error . (Hay buenas razones por las que tenemos esta situación extraña, principalmente relacionada con evitar futuros cambios de ruptura y evitar situaciones de "gallina y huevo", pero en su caso estamos teniendo un comportamiento algo desafortunado como resultado).

Básicamente, la regla aquí es que existe una conversión de X a un tipo de delegado sin parámetros si la resolución de sobrecarga en una llamada de la forma X() tendría éxito. Claramente tal llamada tendría éxito, y por lo tanto existe una conversión. En realidad, usar esa conversión es un error porque los tipos de retorno no coinciden, pero la resolución de sobrecarga siempre ignora los tipos de retorno .

Por lo tanto, existe una conversión de X a Func<IEnumerable<String> , y por lo tanto esa sobrecarga es un candidato aplicable.

Obviamente, por la misma razón, la otra sobrecarga también es un candidato aplicable.

Paso tres: Ahora tenemos dos candidatos aplicables. Cuál es mejor"?

El que es "mejor" es el que tiene el tipo más específico . Si tiene dos candidatos aplicables, M(Animal) y M(Giraffe) elegimos la versión de Giraffe porque una Giraffe es más específica que un Animal. Sabemos que la jirafa es más específica porque cada jirafa es un animal, pero no cada animal es una jirafa.

Pero en tu caso ninguno de los dos es más específico que el otro. No hay conversión entre los dos tipos de funciones.

Por lo tanto, ninguno es mejor, por lo que la resolución de sobrecarga informa un error.

El compilador C # 4 luego tiene lo que parece ser un error, donde su modo de recuperación de error elige a uno de los candidatos de todos modos e informa otro error. No me queda claro por qué está sucediendo eso. Básicamente, está diciendo que la recuperación de errores es elegir la sobrecarga IEnumerable y luego observar que la conversión del grupo de métodos produce un resultado insostenible; a saber, esa cadena no es compatible con IEnumerable<String> .

Toda la situación es bastante desafortunada; podría haber sido mejor decir que no hay una conversión de método-grupo-a-delegado si los tipos de retorno no coinciden. (O bien, que una conversión que produce un error siempre es peor que una conversión que no lo hace). Sin embargo, ahora estamos atascados con ella.

Un dato interesante: las reglas de conversión para las lambdas tienen en cuenta los tipos de devolución. Si dices Foo(()=>X()) entonces hacemos lo correcto. El hecho de que las lambdas y los grupos de métodos tengan diferentes reglas de convertibilidad es bastante desafortunado.

Entonces, resumiendo, el compilador es en realidad una implementación correcta de la especificación en este caso, y este escenario en particular es una consecuencia no deseada de algunas elecciones de especificación posiblemente desafortunadas.

Esto me dejó desconcertado, así que pensé que lo pediría aquí con la esperanza de que un gurú de C # pueda explicármelo.

¿Por qué este código genera un error?

class Program { static void Main(string[] args) { Foo(X); // the error is on this line } static String X() { return "Test"; } static void Foo(Func<IEnumerable<String>> x) { } static void Foo(Func<String> x) { } }

El error en cuestión:

Error 1 The call is ambiguous between the following methods or properties: ''ConsoleApplication1.Program.Foo(System.Func<System.Collections.Generic.IEnumerable<string>>)'' and ''ConsoleApplication1.Program.Foo(System.Func<string>)'' C:/Users/mabster/AppData/Local/Temporary Projects/ConsoleApplication1/Program.cs 12 13 ConsoleApplication1

No importa qué tipo utilizo: si reemplaza las declaraciones de "Cadena" por "int" en ese código, obtendrá el mismo tipo de error. Es como que el compilador no puede distinguir la diferencia entre Func<T> y Func<IEnumerable<T>> .

¿Alguien puede arrojar algo de luz sobre esto?


Su código requiere que "magia" tenga lugar dos veces, una vez para convertir del grupo de métodos nombrado a un delegado y una vez para realizar la resolución de sobrecarga.

A pesar de que solo tiene un método llamado X , las reglas del compilador se crean para el caso cuando existen múltiples.

Además, dado que los delegados no tienen que coincidir exactamente con la firma del método, la complejidad aumenta aún más. Además de eso, cualquier método dado se puede convertir a un número ilimitado de diferentes tipos de delegados con firmas idénticas.

Su caso particular parece bastante sencillo, pero el caso general es muy difícil, por lo que el lenguaje no lo permite.

Si haces parte del trabajo a mano, resolverás el problema. p.ej

Func<string> d = X; Foo(d);

debe compilar bien