web-dev-qa-db-fra.com

nom de génériques

J'expérimentais avec nameof avec des génériques. Je n'ai pas obtenu le résultat que j'attendais. Je ne sais pas si cela fait partie de la spécification ou non.

class MainClass
{
    public static void Main (string[] args)
    {
        Console.WriteLine ($"Hello { nameof(FooBar<string>)! }");
    }
}

class FooBar<T> { }

La sortie que j'obtiens est

Bonjour FooBar!

Je m'attendrais à quelques détails sur les paramètres de type.

Je l'ai essayé avec une méthode et cela échoue avec une erreur de compilation:

class MainClass
{
    public static void Main (string[] args)
    {
        Console.WriteLine ($"Hello { nameof(Do<string>) }");
    }

    public static T Do<T>() {}
}

Erreur CS8084: Un argument à l'opérateur nameof ne peut pas être un groupe de méthodes avec des arguments de type (CS8084) (foo)

Est-ce parce que nameof est une construction à la compilation et que les génériques sont des types initialisés au moment de l'exécution? Ou existe-t-il une autre limitation?

28
Daniel A. White

Je m'attendrais à quelques détails sur les paramètres de type

Le "spec" dit :

Résultat de nameof. Le résultat de nameof dépend des symboles auxquels son argument était lié:

Un ou plusieurs membres: si tous les membres ont le même nom de métadonnées, le résultat de nameof est ce nom; sinon c'est une erreur "Cet argument fait référence à plusieurs éléments avec des noms différents". Le nom de métadonnées d'un membre I orI <isA1 ... AK> `est simplement" I "après l'application des transformations d'identificateur standard.

Le <T> le paramètre est supprimé en raison de transformations d'identificateurs standard (section §2.4.2 dans la spécification C #) qui ne permettent pas <> comme identificateurs valides. Tout premier @ est supprimé, puis les séquences d'échappement Unicode sont transformées, puis tous les caractères de mise en forme sont supprimés. Bien sûr, cela se produit toujours au moment de la compilation. Vous pouvez également le voir lorsque vous essayez d'imprimer le nom d'un type générique:

typeof(List<string>).Name;

Aura pour résultat:

List`1

Est-ce parce que nameof est une construction au moment de la compilation et que les génériques sont des types initialisés au moment de l'exécution? Ou existe-t-il une autre limitation?

La deuxième erreur est spécifiée comme non valide par conception pour éviter les complications de résolution de surcharge dans nameof:

Autoriser les arguments de type générique? Vraisemblablement "oui" lors de la désignation d'un type, car c'est ainsi que la liaison d'expression fonctionne déjà. Et sans doute "non". lors de la dénomination d'un groupe de méthodes puisque des arguments de type sont utilisés/déduits pendant la résolution de surcharge, et il serait également déroutant de devoir traiter cela dans nameof.

Nous pouvons le voir clairement dans la base de code roslyn:

private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax node, 
                                                   DiagnosticBag diagnostics)
{
    CheckFeatureAvailability(node.GetLocation(), MessageID.IDS_FeatureNameof, diagnostics);

    var argument = node.ArgumentList.Arguments[0].Expression;
    string name = "";

    // We relax the instance-vs-static requirement for top-level member access expressions by creating a NameofBinder binder.
    var nameofBinder = new NameofBinder(argument, this);
    var boundArgument = nameofBinder.BindExpression(argument, diagnostics);

    if (!boundArgument.HasAnyErrors && CheckSyntaxForNameofArgument(argument, out name, diagnostics) && boundArgument.Kind == BoundKind.MethodGroup)
    {
        var methodGroup = (BoundMethodGroup)boundArgument;
        if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty)
        {
            // method group with type parameters not allowed
            diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location);
        }
        else
        {
            nameofBinder.EnsureNameofExpressionSymbols(methodGroup, diagnostics);
        }
    }

    return new BoundNameOfOperator(node, boundArgument, ConstantValue.Create(name), Compilation.GetSpecialType(SpecialType.System_String));
}
23
Yuval Itzchakov