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?
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
)
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....");
}
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 });
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.
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..
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)
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
_.
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.
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!
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.
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.
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 :)
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 ...
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.
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.