wake-up-neo.com

Was ist der Zweck von nameof?

Version 6.0 hat eine neue Funktion von nameof, aber ich kann den Zweck nicht verstehen, da nur der Variablenname verwendet und beim Kompilieren in einen String geändert wird.

Ich dachte, es könnte einen Zweck haben, wenn ich <T> verwende, aber wenn ich versuche, nameof(T) zu verwenden, druckt es mir nur T anstelle des verwendeten Typs.

Irgendeine Idee zu dem Zweck?

230
atikot

Was ist mit Fällen, in denen Sie den Namen einer Eigenschaft wiederverwenden möchten, beispielsweise beim Auslösen einer Ausnahme basierend auf einem Eigenschaftsnamen oder beim Behandeln eines PropertyChanged -Ereignisses? Es gibt zahlreiche Fälle, in denen Sie den Namen der Immobilie haben möchten.

Nehmen Sie dieses Beispiel:

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

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

Im ersten Fall wird durch das Umbenennen von SomeProperty auch der Name der Eigenschaft geändert, oder die Kompilierung wird abgebrochen. Der letzte Fall tut es nicht.

Dies ist ein sehr nützlicher Weg, um Ihren Code kompilieren und fehlerfrei zu halten.

(Ein sehr netter Artikel von Eric Lippert warum infoof es nicht geschafft hat, während nameof)

283
Patrick Hofman

Es ist wirklich nützlich für ArgumentException und seine Derivate:

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

Wenn nun jemand den Namen des Parameters input überarbeitet, wird die Ausnahme ebenfalls auf dem neuesten Stand gehalten.

Es ist auch an einigen Stellen nützlich, an denen zuvor Reflektion verwendet werden musste, um die Namen von Eigenschaften oder Parametern abzurufen.

In Ihrem Beispiel ruft nameof(T) den Namen des Typparameters ab - dies kann auch nützlich sein:

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

Eine andere Verwendung von nameof ist für Aufzählungen - normalerweise verwenden Sie .ToString(), wenn Sie den Zeichenfolgennamen einer Aufzählung möchten:

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

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

> "FooBar"

Dies ist relativ langsam, da .Net den Enum-Wert (d. H. 7) enthält und den Namen zur Laufzeit findet.

Verwenden Sie stattdessen nameof:

Console.WriteLine(nameof(MyEnum.FooBar))

> "FooBar"

Jetzt ersetzt .Net den Namen der Aufzählung beim Kompilieren durch einen String.


Eine weitere Verwendung ist für Dinge wie INotifyPropertyChanged und Protokollierung - in beiden Fällen möchten Sie, dass der Name des Members, das Sie aufrufen, an eine andere Methode übergeben wird:

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

Oder...

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

Ein weiterer Anwendungsfall, in dem die Funktion nameof von C # 6.0 nützlich wird - Betrachten Sie eine Bibliothek wie Dapper , die DB erstellt Abfragen viel einfacher. Obwohl dies eine großartige Bibliothek ist, müssen Sie Eigenschafts-/Feldnamen in der Abfrage fest codieren. Dies bedeutet, dass Sie bei einer Umbenennung Ihrer Eigenschaft/Ihres Feldes möglicherweise vergessen, die Abfrage zu aktualisieren, um neue Feldnamen zu verwenden. Mit der String-Interpolation und den Funktionen von nameof wird Code viel einfacher zu warten und typsicher.

Aus dem im Link angegebenen Beispiel

ohne nameof

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

mit nameof

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

Ihre Frage drückt bereits den Zweck aus. Sie müssen sehen, dass dies nützlich sein kann, um Ausnahmen zu protokollieren oder auszulösen.

zum Beispiel.

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

das ist gut, wenn ich den Namen der Variablen ändere, bricht der Code stattdessen ab oder es wird eine Ausnahme mit einer falschen Meldung zurückgegeben.


Natürlich sind die Verwendungen nicht auf diese einfache Situation beschränkt. Sie können nameof immer dann verwenden, wenn es sinnvoll ist, den Namen einer Variablen oder Eigenschaft zu codieren.

Die Verwendungsmöglichkeiten sind vielfältig, wenn Sie verschiedene Bindungs- und Reflexionssituationen berücksichtigen. Dies ist eine hervorragende Möglichkeit, Laufzeitfehler zum Kompilieren der Zeit zu bringen.

21
Jodrell

Der häufigste Anwendungsfall, an den ich denken kann, ist die Arbeit mit der INotifyPropertyChanged -Oberfläche. (Grundsätzlich verwendet alles, was mit WPF und Bindungen zu tun hat, diese Schnittstelle.)

Schauen Sie sich dieses Beispiel an:

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)));           
        }
    }
}

Wie Sie auf die alte Weise sehen können, müssen wir einen String übergeben, um anzugeben, welche Eigenschaft geändert wurde. Mit nameof können wir den Namen der Eigenschaft direkt verwenden. Dies scheint keine große Sache zu sein. Aber stellen Sie sich vor, was passiert, wenn jemand den Namen der Eigenschaft Foo ändert. Wenn Sie eine Zeichenfolge verwenden, funktioniert die Bindung nicht mehr, der Compiler warnt Sie jedoch nicht. Bei Verwendung von nameof erhalten Sie einen Compilerfehler, dass es keine Eigenschaft/kein Argument mit dem Namen Foo gibt.

Beachten Sie, dass einige Frameworks Reflection Magic verwenden, um den Namen der Eigenschaft abzurufen, aber jetzt haben wir den Namen, der nicht mehr erforderlich ist..

13
Roy T.

Die gebräuchlichste Verwendung ist die Eingabevalidierung, z

//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));
}

Wenn Sie im ersten Fall die Änderung des Parameters par umgestalten, werden Sie wahrscheinlich vergessen, dies in der ArgumentNullException zu ändern. Mit nameof müssen Sie sich darüber keine Gedanken machen.

Siehe auch: nameof (C # und Visual Basic-Referenz)

8
Massimo Prota

Das ASP.NET Core MVC-Projekt verwendet nameof in den Methoden AccountController.cs und ManageController.cs , um auf RedirectToAction zu verweisen eine Aktion in der Steuerung.

Beispiel:

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

Dies bedeutet:

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

und führt den Benutzer zur Aktion 'Index' im 'Home'-Controller, d. h. _/Home/Index_.

7
Fred

Wie bereits erwähnt, fügt der Operator nameof den Namen des Elements in den Quellcode ein.

Ich möchte hinzufügen, dass dies in Bezug auf das Refactoring eine wirklich gute Idee ist, da es das Refactoring dieser Zeichenfolge sicher macht. Bisher habe ich eine statische Methode verwendet, bei der Reflektion für denselben Zweck verwendet wurde, die sich jedoch auf die Laufzeitleistung auswirkt. Der Operator nameof hat keine Auswirkungen auf die Laufzeitleistung. Es erledigt seine Arbeit zur Kompilierungszeit. Wenn Sie sich den Code MSIL ansehen, finden Sie den eingebetteten String. Siehe die folgende Methode und ihren disassemblierten Code.

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

Dies kann jedoch ein Nachteil sein, wenn Sie vorhaben, Ihre Software zu verschleiern. Nach der Verschleierung stimmt die eingebettete Zeichenfolge möglicherweise nicht mehr mit dem Namen des Elements überein. Mechanismen, die sich auf diesen Text stützen, brechen ab. Beispiele dafür, einschließlich, aber nicht beschränkt auf: Reflection, NotifyPropertyChanged ...

Das Ermitteln des Namens zur Laufzeit kostet etwas Leistung, ist aber sicher für die Verschleierung. Wenn eine Verschleierung weder erforderlich noch geplant ist, würde ich die Verwendung des Operators nameof empfehlen.

6
cel sharp

Bedenken Sie, dass Sie eine Variable in Ihrem Code verwenden und den Namen der Variablen abrufen müssen, und sagen wir, dass Sie sie drucken müssen

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

Und wenn dann jemand den Code überarbeitet und einen anderen Namen für "myVar" verwendet, müsste er/sie nach dem Zeichenfolgenwert in Ihrem Code Ausschau halten und ihn entsprechend ändern.

Stattdessen, wenn Sie hatten

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

Es würde helfen, automatisch umzugestalten!

5
cnom

Der MSDN-Artikel listet unter anderem das MVC-Routing (das Beispiel, das das Konzept für mich wirklich angeklickt hat) auf. Der (formatierte) Beschreibungsabschnitt lautet:

  • Wenn Fehler im Code gemeldet werden,
  • Anschließen von Model-View-Controller (MVC) -Links,
  • Auslösen von Ereignissen mit geänderter Eigenschaft usw.,

sie möchten häufig den Zeichenfolgennamen einer Methode erfassen. Die Verwendung von nameof hilft , Ihren Code beim Umbenennen von Definitionen gültig zu halten.

Bevor Sie String-Literale verwenden mussten, um auf Definitionen zu verweisen, ist spröde beim Umbenennen von Codeelementen , da Tools diese Zeichenfolgenliterale nicht überprüfen können.

Die akzeptierten/bestbewerteten Antworten geben bereits einige ausgezeichnete konkrete Beispiele.

4
brichins

Mit dem Operator nameof wird der Quellenname der Artefakte angegeben.

Normalerweise ist der Name der Quelle derselbe wie der Name der Metadaten:

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));
    }
}

Dies ist jedoch möglicherweise nicht immer der Fall:

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

Oder:

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

Eine Verwendung, die ich ihm gegeben habe, ist das Benennen von Ressourcen:

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

Tatsache ist, dass ich in diesem Fall nicht einmal die generierten Eigenschaften benötigte, um auf die Ressourcen zuzugreifen. Jetzt muss ich beim Kompilieren überprüfen, ob die Ressourcen vorhanden sind.

3
Paulo Morgado

Ein weiterer Anwendungsfall von nameof besteht darin, Registerkarten zu überprüfen. Anstatt den Index zu überprüfen, können Sie die Name -Eigenschaft der Registerkarten folgendermaßen überprüfen:

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

Weniger chaotisch :)

0
diedrop

Eine Verwendung des Schlüsselworts nameof ist die Einstellung von Binding in wpf programmgesteuert.

um Binding einzustellen, müssen Sie Path mit einem String einstellen. Mit dem Schlüsselwort nameof können Sie die Option Refactor verwenden.

Wenn Sie beispielsweise die Abhängigkeitseigenschaft IsEnable in Ihrem UserControl haben und diese an IsEnable von einigen CheckBox in Ihrem UserControl binden möchten, können Sie diese verwenden Diese beiden Codes:

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

und

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

Es ist offensichtlich, dass der erste Code nicht refaktoriert werden kann, aber der zweite ...

0
Mehdi Khademloo

Dies hat Vorteile, wenn Sie ASP.Net MVC verwenden. Wenn Sie HTML-Helfer verwenden, um ein Steuerelement in der Ansicht zu erstellen, werden Eigenschaftsnamen in der Namensattributierung der HTML-Eingabe verwendet:

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

Es macht so etwas:

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

Wenn Sie also Ihre Eigenschaft in der Validate-Methode validieren müssen, können Sie dies tun:

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

Wenn Sie Ihre Immobilie mit Refactoring-Tools umbenennen, wird Ihre Validierung nicht beeinträchtigt.

0
dgtlfx

Bisher haben wir so etwas benutzt:

// 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)
{
    ...
}

Grund - Kompilierzeit Sicherheit. Niemand kann unbemerkt die Eigenschaft umbenennen und die Codelogik unterbrechen. Jetzt können wir nameof () verwenden.

0
QtRoS