web-dev-qa-db-fra.com

Quel est le but de nameof?

La version 6.0 a une nouvelle fonctionnalité de nameof, mais je ne comprends pas son objectif, car elle prend simplement le nom de la variable et la change en chaîne lors de la compilation.

Je pensais que cela aurait un intérêt à utiliser <T>, mais lorsque j'essaie de nameof(T), il m'imprime simplement un T à la place du type utilisé.

Une idée sur le but?

230
atikot

Qu'en est-il des cas où vous souhaitez réutiliser le nom d'une propriété, par exemple lors du lancement d'une exception basée sur un nom de propriété ou de la gestion d'un événement PropertyChanged? Il existe de nombreux cas où vous voudriez avoir le nom de la propriété.

Prenons cet exemple:

switch (e.PropertyName)
{
    case nameof(SomeProperty):
    { break; }

    // opposed to
    case "SomeOtherProperty":
    { break; }
}

Dans le premier cas, renommer SomeProperty modifiera également le nom de la propriété ou interrompra la compilation. Le dernier cas ne.

C'est un moyen très utile de garder votre code en cours de compilation et sans bug (en quelque sorte).

(A très bel article d'Eric Lippert pourquoi infoof ne l'a pas fait, alors que nameof l'a fait)

283
Patrick Hofman

C'est vraiment utile pour ArgumentException et ses dérivés:

public string DoSomething(string input) 
{
    if(input == null) 
    {
        throw new ArgumentNullException(nameof(input));
    }
    ...

Désormais, si quelqu'un refactorise le nom du paramètre input, l'exception sera également mise à jour.

Il est également utile dans certains endroits où il fallait auparavant utiliser la réflexion pour obtenir les noms de propriétés ou de paramètres.

Dans votre exemple, nameof(T) obtient le nom du paramètre type. Cela peut également être utile:

throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");

Une autre utilisation de nameof est pour les énumérations - généralement si vous voulez le nom de chaîne d'une énumération, vous utilisez .ToString():

enum MyEnum { ... FooBar = 7 ... }

Console.WriteLine(MyEnum.FooBar.ToString());

> "FooBar"

Cela est en fait relativement lent car .Net conserve la valeur enum (c'est-à-dire 7) et trouve le nom au moment de l'exécution.

Utilisez plutôt nameof:

Console.WriteLine(nameof(MyEnum.FooBar))

> "FooBar"

Maintenant, .Net remplace le nom enum par une chaîne lors de la compilation.


Encore une autre utilisation est pour des choses comme INotifyPropertyChanged et la journalisation - dans les deux cas, vous voulez que le nom du membre que vous appelez soit passé à une autre méthode:

// Property with notify of change
public int Foo
{
    get { return this.foo; }
    set
    {
        this.foo = value;
        PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
    }
}

Ou...

// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
    Log(nameof(DoSomething), "Message....");
}
162
Keith

Un autre cas d'utilisation où la fonctionnalité nameof de C # 6.0 devient pratique - Considérons une bibliothèque comme Dapper qui fabrique DB les récupérations beaucoup plus faciles. Bien que ce soit une excellente bibliothèque, vous devez coder en dur les noms de propriété/champ dans la requête. Cela signifie que si vous décidez de renommer votre propriété/votre champ, il y a de fortes chances que vous oubliez de mettre à jour la requête pour utiliser de nouveaux noms de champs. Avec l'interpolation de chaîne et les fonctions nameof, le code devient beaucoup plus facile à gérer et à typer.

De l'exemple donné dans le lien

sans nomof

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });

avec nameof

var dog = connection.Query<Dog>($"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id", new { Age = (int?)null, Id = guid });
24
sateesh

Votre question exprime déjà le but. Vous devez voir que cela peut être utile pour la journalisation ou le lancement d’exceptions.

par exemple.

public void DoStuff(object input)
{
    if (input == null)
    {
        throw new ArgumentNullException(nameof(input));
    }
}

c'est bien, si je change le nom de la variable, le code sera cassé à la place ou retournera une exception avec un message incorrect.


Bien entendu, les utilisations ne se limitent pas à cette situation simple. Vous pouvez utiliser nameof chaque fois qu'il serait utile de coder le nom d'une variable ou d'une propriété.

Les utilisations sont multiples lorsque l’on considère diverses situations de liaison et de réflexion. C’est un excellent moyen d’apporter les erreurs d’exécution pour compiler le temps.

21
Jodrell

Le cas d'utilisation le plus courant auquel je puisse penser est lorsque vous travaillez avec l'interface INotifyPropertyChanged. (Fondamentalement, tout ce qui concerne WPF et les liaisons utilise cette interface)

Jetez un oeil à cet exemple:

public class Model : INotifyPropertyChanged
{
    // From the INotifyPropertyChanged interface
    public event PropertyChangedEventHandler PropertyChanged;

    private string foo;
    public String Foo
    {
        get { return this.foo; }
        set
        {
            this.foo = value;
            // Old code:
            PropertyChanged(this, new PropertyChangedEventArgs("Foo"));

            // New Code:
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));           
        }
    }
}

Comme vous pouvez le voir à l'ancienne, nous devons passer une chaîne pour indiquer quelle propriété a changé. Avec nameof, nous pouvons utiliser directement le nom de la propriété. Cela pourrait ne pas sembler un gros problème. Mais image ce qui se passe quand quelqu'un change le nom de la propriété Foo. Lorsque vous utilisez une chaîne, la liaison ne fonctionnera plus, mais le compilateur ne vous avertira pas. Lorsque vous utilisez nameof, vous obtenez une erreur de compilation qui indique qu'il n'y a pas de propriété/argument portant le nom Foo.

Notez que certains frameworks utilisent une magie de réflexion pour obtenir le nom de la propriété, mais nous avons maintenant le nom qui n'est plus nécessaire.

13
Roy T.

L’utilisation la plus courante sera la validation des entrées, telle que

//Currently
void Foo(string par) {
   if (par == null) throw new ArgumentNullException("par");
}

//C# 6 nameof
void Foo(string par) {
   if (par == null) throw new ArgumentNullException(nameof(par));
}

Dans le premier cas, si vous refactorisez la méthode en changeant le nom du paramètre par , vous oublierez probablement de le changer dans le ArgumentNullException . Avec nameof , vous n'avez pas à vous en préoccuper.

Voir aussi: nameof (Référence C # et Visual Basic)

8
Massimo Prota

Le projet ASP.NET Core MVC utilise nameof dans les AccountController.cs et ManageController.cs avec la méthode RedirectToAction à référencer. une action dans le contrôleur.

Exemple:

_return RedirectToAction(nameof(HomeController.Index), "Home");
_

Cela se traduit par:

_return RedirectToAction("Index", "Home");
_

et conduit l'utilisateur à l'action 'Index' dans le contrôleur 'Accueil', c'est-à-dire _/Home/Index_.

7
Fred

Comme d'autres l'ont déjà souligné, l'opérateur nameof insère le nom que l'élément a été donné dans le code source.

Je voudrais ajouter que c’est une très bonne idée en termes de refactoring car cela rend le refactoring de chaînes sûr. Auparavant, j'utilisais une méthode statique qui utilisait la réflexion dans le même but, mais qui avait un impact sur les performances d'exécution. L'opérateur nameof n'a aucun impact sur les performances d'exécution; il fait son travail au moment de la compilation. Si vous regardez le code MSIL, vous trouverez la chaîne incorporée. Voir la méthode suivante et son code désassemblé.

static void Main(string[] args)
{
    Console.WriteLine(nameof(args));
    Console.WriteLine("regular text");
}

// striped nops from the listing
IL_0001 ldstr args
IL_0006 call System.Void System.Console::WriteLine(System.String)
IL_000C ldstr regular text
IL_0011 call System.Void System.Console::WriteLine(System.String)
IL_0017 ret

Cependant, cela peut être un inconvénient si vous envisagez d’obscurcir votre logiciel. Après obscurcissement, la chaîne incorporée peut ne plus correspondre au nom de l'élément. Les mécanismes qui reposent sur ce texte vont casser. Les exemples pour cela, y compris mais sans s'y limiter, sont: Reflection, NotifyPropertyChanged ...

Déterminer le nom pendant l'exécution coûte un peu de performance, mais est sans danger pour l'obscurcissement. Si l'obscurcissement n'est ni requis ni prévu, je vous recommande d'utiliser l'opérateur nameof.

6
cel sharp

Considérez que vous utilisez une variable dans votre code et que vous devez obtenir le nom de la variable et, disons, l’imprimer, vous devriez avoir à utiliser

int myVar = 10;
print("myVar" + " value is " + myVar.toString());

Et si ensuite quelqu'un refactorise le code et utilise un autre nom pour "myVar", il/elle devra surveiller la valeur de chaîne dans votre code et la modifier en conséquence.

Au lieu de cela si vous aviez

print(nameof(myVar) + " value is " + myVar.toString());

Il serait utile de refactoriser automatiquement!

5
cnom

L'article MSDN répertorie le routage MVC (l'exemple qui a véritablement cliqué sur le concept pour moi) parmi plusieurs autres. Le paragraphe de description (formaté) se lit comme suit:

  • Lorsque vous signalez des erreurs dans le code,
  • reliant des liens modèle-vue-contrôleur (MVC),
  • propriété de déclenchement événements modifiés, etc.,

vous voulez souvent capturer le nom de chaîne d'une méthode . En utilisant nameof , gardez votre code valide lorsque vous renommez des définitions.

Avant de devoir utiliser des littéraux de chaîne pour faire référence à des définitions, , ce qui est fragile lors du changement de nom d'éléments de code , car les outils ne savent pas vérifier ces littéraux de chaîne.

Les réponses acceptées/les mieux notées donnent déjà plusieurs excellents exemples concrets.

4
brichins

Le but de l'opérateur nameof est de fournir le nom source des artefacts.

Généralement, le nom de la source est identique à celui des métadonnées:

public void M(string p)
{
    if (p == null)
    {
        throw new ArgumentNullException(nameof(p));
    }
    ...
}

public int P
{
    get
    {
        return p;
    }
    set
    {
        p = value;
        NotifyPropertyChanged(nameof(P));
    }
}

Mais cela peut ne pas toujours être le cas:

using i = System.Int32;
...
Console.WriteLine(nameof(i)); // prints "i"

Ou:

public static string Extension<T>(this T t)
{
    return nameof(T); returns "T"
}

Une utilisation que je lui ai donnée est pour nommer des ressources:

[Display(
    ResourceType = typeof(Resources),
    Name = nameof(Resources.Title_Name),
    ShortName = nameof(Resources.Title_ShortName),
    Description = nameof(Resources.Title_Description),
    Prompt = nameof(Resources.Title_Prompt))]

Le fait est que, dans ce cas, je n'avais même pas besoin des propriétés générées pour accéder aux ressources, mais maintenant, je vérifie à la compilation que les ressources existent.

3
Paulo Morgado

Un autre cas d'utilisation de nameof consiste à vérifier les pages à onglet. Au lieu de vérifier l'index, vous pouvez vérifier la propriété Name des pages à onglet comme suit:

if(tabControl.SelectedTab.Name == nameof(tabSettings))
{
    // Do something
}

Moins salissant :)

0
diedrop

Le mot-clé nameof sert notamment à définir Binding dans wpf par programmation.

pour définir Binding, vous devez définir Path avec une chaîne, et avec le mot clé nameof, il est possible d'utiliser l'option Refactor.

Par exemple, si vous avez la propriété de dépendance IsEnable dans votre UserControl et que vous souhaitez la lier à IsEnable de certains CheckBox dans votre UserControl, vous pouvez utiliser ces deux codes:

CheckBox chk = new CheckBox();
Binding bnd = new Binding ("IsEnable") { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);

et

CheckBox chk = new CheckBox();
Binding bnd = new Binding (nameof (IsEnable)) { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);

Il est évident que le premier code ne peut pas être refacté, mais le second ...

0
Mehdi Khademloo

Cela présente un avantage lorsque vous utilisez ASP.Net MVC. Lorsque vous utilisez l'assistant HTML pour créer un contrôle dans la vue, il utilise les noms de propriété dans le nom d'attribution d'entrée HTML:

@Html.TextBoxFor(m => m.CanBeRenamed)

Cela fait quelque chose comme ça:

<input type="text" name="CanBeRenamed" />

Alors maintenant, si vous devez valider votre propriété dans la méthode Validate, vous pouvez le faire:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
  if (IsNotValid(CanBeRenamed)) {
    yield return new ValidationResult(
      $"Property {nameof(CanBeRenamed)} is not valid",
      new [] { $"{nameof(CanBeRenamed)}" })
  }
}

Si vous renommez votre propriété à l'aide d'outils de refactoring, votre validation ne sera pas rompue.

0
dgtlfx

Auparavant, nous utilisions quelque chose comme ça:

// Some form.
SetFieldReadOnly( () => Entity.UserName );
...
// Base form.
private void SetFieldReadOnly(Expression<Func<object>> property)
{
    var propName = GetPropNameFromExpr(property);
    SetFieldsReadOnly(propName);
}

private void SetFieldReadOnly(string propertyName)
{
    ...
}

Reason - Compile time safety. Personne ne peut renommer la propriété et casser la logique de code en silence. Nous pouvons maintenant utiliser nameof ().

0
QtRoS