57 votes

Les arguments nommés et de l'inférence de type générique en C# 4.0

J'avais été à la programmation dans le cadre de l'hypothèse que, lors de l'appel d'une méthode en C# 4.0, la fourniture de noms pour vos arguments n'auraient pas d'incidence sur l'issue à moins que vous ont été "sauter" d'un ou de plusieurs paramètres facultatifs.

J'ai donc été un peu surpris de découvrir le comportement suivant:

Une méthode qui prend un Func<T>, l'exécute et renvoie le résultat:

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

Et une autre méthode à partir de laquelle la méthode ci-dessus est visible:

static void Main()
{
    string s;

l'appel de F (sans arguments nommés) compile sans problèmes:

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

Et lors de l'utilisation d'un argument nommé...

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

... au-dessus de la ligne de code en utilisant le type explicite argument encore compile sans problèmes. Et peut-être il n'est pas surprenant, si vous avez ReSharper installé, il va suggèrent que l "argument de Type spécification est redondante".

Cependant, lors de la suppression de l'argument de type...

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

le compilateur C# va signaler cette erreur:

Le type des arguments de la méthode 'Programme.F(Système D'.Func)' ne peut pas être déduit à partir de l'utilisation. Essayez de spécifier le type des arguments explicitement.

Est-il une explication logique de cette interaction entre les arguments nommés et l'inférence de type?

Est ce comportement documenté quelque part dans la spécification du langage?

Je comprends qu'il n'est pas nécessaire pour moi de nom de l'argument. Cependant, j'ai découvert ce comportement dans des situations beaucoup plus complexes où j'ai pensé qu'il pourrait être judicieux de nommer les arguments dans mon appel de méthode interne des fins de documentation. Je ne demande pas comment contourner ce problème. Je suis en train d'essayer de comprendre certaines subtilités de la langue.

Pour rendre les choses plus intéressantes, j'ai découvert que la suite de toutes les compile sans problèmes:

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

En passant, j'ai observé le même comportement avec les méthodes statiques. J'ai juste choisi d'utiliser des méthodes statiques pour prendre l'exemple ici, un peu plus courte.

16voto

Akash Kava Points 18026

L'inférence n'est pas quelque chose qui va travailler à plusieurs niveaux imbriqués dans la compilation. C'est une supposition basée sur des arguments fournis. Je sens le compilateur auteurs ne considèrent pas l'inférence de la logique avec des paramètres nommés. Si vous envisagez d'arbre de syntaxe abstraite, Même si la logique est la même, mais les deux F(()=>"xyz") Et F(f:()=>"xyz") Sont différents de l'arbre de syntaxe abstraite à partir du compilateur point de vue.

Je pense que c'est juste une règle oubliée par le compilateur concepteur où même le compilateur lui-même est un programme avec un énorme ensemble de règles. Une règle correspond à premier cas, mais pas de règle correspond à la deuxième. Il peut être conceptuellement droit, mais le compilateur est juste un programme et de toutes les règles de l'homme codé.

Ok, je suppose que comme d'autres l'ont déterminé, son bug et doit être signalé à Microsoft !!

6voto

Mark Hurd Points 4746

Veux juste vous faire savoir que c' est un bug spécifique à C# (et @leppie j'ai confirmé elle ne parviennent pas à la norme csc.exe, pas même dans Visual Studio). De manière redondante en spécifiant un nom d'argument ne devrait pas provoquer un changement dans le comportement de tous.

Le bug a été signalé à Microsoft Connect.

L'équivalent VB fonctionne très bien (parce qu'il n'compiler, j'ai ajouté un peu de confirmer l'exécution de comportement est comme prévu):

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

Sortie:

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

-1voto

ferosekhanj Points 691

L'appel d'une fonction avec des paramètres nommés et sans paramètres nommés ne sont pas les mêmes. Dans le cas de paramètres nommés compilateur prend différentes chemin depuis qu'il a besoin de régler les paramètres nommés en premier. Dans votre cas, le compilateur est à essayer de comprendre paramètre f avant de résoudre le T dans F, donc il est de demander au programmeur d'indiquer explicitement que.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X