whats news new microsoft features evolution docs c# generics c#-4.0 compiler-errors type-inference

news - versions of c#



Argumentos con nombre e inferencia de tipo genérico en C#4.0 (3)

La inferencia no es algo que funcionará en muchos niveles anidados en la compilación. Es una especie de suposición basada en los argumentos proporcionados. Siento que los escritores del compilador no consideraron deducir la lógica junto con el parámetro nombrado. Si considera el árbol sintáctico abstracto, aunque la lógica sea la misma, pero tanto F (() => "xyz") como F (f: () => "xyz") son diferentes árboles sintácticos abstractos desde la perspectiva del compilador.

Siento que es solo una regla que falla el diseñador de compiladores donde incluso el propio compilador es un programa con un gran conjunto de reglas. Una regla coincide con el primer caso, pero ninguna regla coincide con la segunda. Puede ser conceptualmente correcto, pero el compilador es solo un programa y todas las reglas están codificadas por el ser humano.

Ok, supongo que como otros han determinado, es un error y debería ser reportado a Microsoft.

Había estado programando bajo el supuesto de que, cuando se llama a un método en C # 4.0, el suministro de nombres para sus argumentos no afectaría el resultado, a menos que al hacerlo se "saltó" uno o más parámetros opcionales.

Así que me sorprendió un poco descubrir el siguiente comportamiento:

Dado un método que toma un Func<T> , lo ejecuta y devuelve el resultado:

public static T F<T>(Func<T> f) { return f(); }

Y otro método desde el cual el método anterior es visible:

static void Main() { string s;

llamando a F (sin argumentos nombrados) compila sin ningún problema:

s = F<string>(() => "hello world"); // with explicit type argument <string> s = F(() => "hello world"); // with type inference

Y cuando se utiliza un argumento con nombre ...

s = F<string>(f: () => "hello world");

... la línea de código anterior utilizando el argumento de tipo explícito aún se compila sin problemas. Y tal vez no demasiado sorprendente, si tiene ReSharper instalado, sugerirá que la "especificación del argumento Tipo es redundante".

Sin embargo, al eliminar el argumento de tipo ...

s = F(f: () => "hello world");

el compilador C # reportará este error:

Los argumentos de tipo para el método ''Program.F (System.Func)'' no se pueden deducir del uso. Intente especificar los argumentos de tipo explícitamente.

¿Hay una explicación lógica para esta interacción entre los argumentos nombrados y la inferencia de tipo?

¿Este comportamiento está documentado en alguna parte de la especificación del lenguaje?

Entiendo que no es necesario para mí nombrar el argumento. Sin embargo, descubrí este comportamiento en un escenario mucho más complejo en el que pensé que podría tener sentido nombrar los argumentos en mi llamada de método para fines de documentación interna. No estoy preguntando cómo solucionar este problema. Estoy tratando de entender algunos de los puntos más finos del lenguaje.

Para hacer las cosas más interesantes, descubrí que las siguientes compilaciones sin problemas:

Func<string> func = () => "hello world"; s = F<string>(func); s = F(func); s = F<string>(f: func); s = F(f: func); }

Por cierto, he observado el mismo comportamiento con métodos no estáticos. Solo elegí usar métodos estáticos para hacer que el ejemplo aquí sea un poco más corto.


Llamar a una función con parámetros nombrados y sin parámetros nombrados no es lo mismo. En el caso de los parámetros nombrados, el compilador toma una ruta diferente ya que primero necesita resolver los parámetros nombrados. En su caso, el compilador intenta descubrir el parámetro f antes de resolver el T en F, por lo que solicita al programador que lo indique explícitamente.


Solo quiero que sepan que este es un error específico de C # (y @leppie he confirmado que falla con el csc.exe estándar, ni siquiera en Visual Studio). Especificar de forma redundante un argumento con nombre no debe causar ningún cambio en el comportamiento.

El error ha sido reportado en Microsoft Connect .

El VB equivalente funciona bien (porque compila, agregué un poco para confirmar que el comportamiento del tiempo de ejecución es el esperado):

Imports System Module Test Function F(Of T)(ByVal fn As Func(Of T)) As T Return fn() End Function Function Inc(ByRef i as Integer) As String i += 1 Return i.ToString End Function Sub Main() Dim s As String s = F(Of String)(Function()"Hello World.") console.writeline(s) s = F(Function()"Hello, World!") console.writeline(s) s = F(Of String)(fn:=Function()"hello world.") console.writeline(s) s = F(fn:=Function()"hello world") console.writeline(s) Dim i As Integer Dim func As Func(Of String) = Function()"hello world " & Inc(i) s = F(Of string)(func) console.writeline(s) s = F(func) console.writeline(s) s = F(Of string)(fn:=func) console.writeline(s) s = F(fn:=func) console.writeline(s) End Sub End Module

Salida:

Hello World. Hello, World! hello world. hello world hello world 1 hello world 2 hello world 3 hello world 4