Nameof'in amacı nedir?


263

Sürüm 6.0 yeni bir özellik var nameof, ama sadece değişken adını alır ve derleme bir dize olarak değiştirir gibi amacını anlayamıyorum.

Kullanırken bir amacı olabileceğini düşündüm <T>ama denediğimde nameof(T)bana Tkullanılan tipin yerine yazdırıyor .

Amaç hakkında bir fikrin var mı?



28
Bunu daha Tönce almanın bir yolu yoktu . Kullanılan türü daha önce almanın bir yolu vardı.
Jon Hanna

Başlangıçta aşırıya kaçmış gibi görünüyordu ve hala kullanmak için zorlayıcı bir neden göremiyorum. Belki bir MVC örneği?
Corey Alix

15
İçinde adı refactory / yeniden adlandırırken kesinlikle yararlı nameof. Ayrıca yazım hatalarını önlemeye yardımcı olur.
bvj

4
Resmi belgeler NameOf : Burada taşındı docs.microsoft.com/en-us/dotnet/csharp/language-reference/... - Ayrıca soruya oldukça iyi bir cevap olarak hizmet anahtar kullanım durumları listeler.
markus s

Yanıtlar:


323

Örneğin, bir özellik adına dayalı istisna atarken veya bir PropertyChangedolayı işlerken, bir mülkün adını yeniden kullanmak istediğiniz durumlara ne dersiniz ? Mülkün adını almak istediğiniz çok sayıda durum vardır.

Bu örneği ele alalım:

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

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

İlk durumda, yeniden adlandırma SomeProperty özelliğin da değiştirir veya derlemeyi bozar. Son durum böyle değil.

Bu kod derleme ve hata ücretsiz (sıralama) tutmak için çok yararlı bir yoludur.

( Eric Lippert'ten çok güzel bir makale neden infoofyapmadı, neden nameofyapmadı)


1
Ben anlıyorum, sadece yeniden birleştirici ekleme isimleri yeniden düzenlerken dizeleri değiştirir, VS benzer işlevselliği olup olmadığından emin değilim.
Ash Burlaczenko

7
Var. Ancak hem Resharper hem de VS, projeler üzerinde çalışmaz. Bu yapar. Aslında, bu daha iyi bir çözümdür.
Patrick Hofman

49
Diğer bir yaygın kullanım örneği, MVC'de yönlendirme nameofve sabit kodlu bir dize yerine eylemin adıdır.
RJ Cuthbertson

2
@sotn Ne istediğini anladığımdan emin değilim. Sizi böyle kullanmanıza engel olan hiçbir şey yoktur public class MyController { public ActionResult Index() { return View(nameof(Index)); } }- ve nameofstatik olmayan üyelerde kullanabilirsiniz (örneğin nameof(MyController.Index)yukarıdaki sınıfı kullanarak arayabilirsiniz ve "Dizin" yayınlar). Msdn.microsoft.com/en-us/library/… adresindeki
RJ Cuthbertson

2
Bunun neden özel olduğunu anlamıyorum. Değişken isimleri her zaman aynıdır, değil mi? Bir örneğiniz olsun ya da olmasın, değişken adları değişmez @sotn
Patrick Hofman

176

ArgumentExceptionVe türevleri için gerçekten yararlıdır :

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

Şimdi birisi inputparametrenin adını yeniden düzenlerse istisna da güncel tutulur.

Özelliklerin veya parametrelerin adlarını almak için daha önce yansımanın kullanılması gereken bazı yerlerde de yararlıdır.

Örnekte nameof(T)tipi parametresinin adını alır - bu çok yararlı olabilir:

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

Diğer bir kullanımı da nameofnumaralandırmalar içindir - genellikle kullandığınız bir numaralandırmanın dize adını istiyorsanız .ToString():

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

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

> "FooBar"

.Net enum değerini (yani 7) tutar ve adı çalışma zamanında bulur.

Bunun yerine kullanın nameof:

Console.WriteLine(nameof(MyEnum.FooBar))

> "FooBar"

.Net derleme zamanında enum adını bir dizeyle değiştirir.


Yine başka bir kullanım INotifyPropertyChangedve günlüğe kaydetme için kullanılır - her iki durumda da, aradığınız üyenin adının başka bir yönteme geçirilmesini istersiniz:

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

Veya...

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

9
Ve bir başka harika özellik daha eklediniz: string interpolation!
Patrick Hofman

1
@PatrickHofman ve typeof(T)benzer koşullarda yararlı olan başka bir derleme zamanı şekeri :-)
Keith

1
Kaybettiğim bir şey gibi bir şey nameofthismethod. Kullanabilirsiniz, Log.Error($"Error in {nameof(DoSomething)}...")ancak bunu başka yöntemlere kopyalayıp yapıştırırsanız, hala başvurduğunu fark etmezsiniz DoSomething. Bu nedenle, yerel değişkenler veya parametrelerle mükemmel şekilde çalışırken, yöntem adı bir sorundur.
Tim Schmelter

3
Varsa bu özelliği kullanıp nameOfkullanamayacağınızı biliyor musunuz [DisplayName]? Örneğin, MVC projeleriyle sık sık enumkullanıyorum[DisplayName]
Luke T O'Brien

2
@AaronLS Evet, oldukça uzmanlaşmış ve sık sık kullanacağınız bir şey değil. Ancak bu throw newtamamen başka bir anti-desen - catchgenç devs ile ortak bir sorun olarak aşırı kullanım buluyorum çünkü sorunu düzeltmek gibi geliyor (çoğu zaman sadece gizlediğinde).
Keith

26

nameofC # 6.0 özelliğinin kullanışlı olduğu başka bir kullanım durumu - DB alımlarını çok daha kolaylaştıran Dapper gibi bir kütüphane düşünün . Bu harika bir kütüphane olsa da, sorgu içindeki özellik / alan adlarını sabitlemeniz gerekir. Bunun anlamı, mülkünüzü / alanınızı yeniden adlandırmaya karar verirseniz, sorguyu yeni alan adlarını kullanacak şekilde güncellemeyi unutacağınız yüksek olasılıktır. Dize enterpolasyonu ve nameofözellikleri ile kodun bakımı ve yazımı çok daha kolay hale gelir.

Bağlantıda verilen örnekten

isimsiz

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

nameof ile

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

3
Dapper'i seviyorum ve dize enterporlasyonlarını gerçekten çok seviyorum, ama IMO bu çok çirkin görünüyor. Bir sütunu yeniden adlandırarak sorguyu kırma riski, bu çirkin sorgulara kıyasla çok küçük görünmektedir. İlk bakışta EF LINQ sorguları yazmayı veya [TableName]. [ColumnName] gibi bir kuralı izlemeyi tercih ettiğimi söyleyebilirim.
drizin

@drizin Bu tür sorguları önlemek için Dapper FluentMap kullanıyorum (ve ayrıca endişelerin ayrılması için)
mamuesstack

21

Sorunuz zaten amacı ifade ediyor. Bunun, günlüğe kaydetme veya istisnalar atmada yararlı olabileceğini görmelisiniz.

Örneğin.

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

Bu iyidir, değişkenin adını değiştirirseniz kod yerine kırılacak veya yanlış bir mesajla bir istisna döndürecektir .


Tabii ki, kullanımlar bu basit durumla sınırlı değildir. nameofBir değişkenin veya özelliğin adını kodlamanın ne zaman yararlı olacağını kullanabilirsiniz .

Çeşitli bağlama ve yansıma durumlarını düşündüğünüzde kullanımlar çok çeşitlidir. Zaman derlemek için çalışma zamanı hataları ne getirmek için mükemmel bir yoldur.


6
@atikot: Ancak, değişkeni yeniden adlandırırsanız, derleyici dizenin artık eşleşmediğini fark etmez.
VEYA Haritacı

1
Aslında bunu hesaba katan resharper kullanıyorum, ama ne demek istediğini anlıyorum.
atikot

4
@atikot, ben de, ama Resharper bir derleyici hatası değil, sadece bir uyarı oluşturur. Kesin ve iyi bir tavsiye arasında bir fark vardır.
Jodrell

1
@atikot ve Resharper günlük iletilerini denetlemez
Jodrell

2
@Jodrell: Ve şüpheliyim, diğer çeşitli kullanımları da kontrol etmiyor - arka planda oluşturulan WPF bağlamaları, özel OnPropertyChangedyöntemler (yerine doğrudan mülkiyet adlarını kabul eden PropertyChangedEventArgs) veya belirli bir arama için yansıma çağrıları üye veya tür?
VEYA Haritacı

13

Aklıma gelen en yaygın kullanım durumu INotifyPropertyChangedarayüzle çalışırken . (Temel olarak WPF ve bağlarla ilgili her şey bu arayüzü kullanır)

Bu örneğe bir göz atın:

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

Eski şekilde görebileceğiniz gibi, hangi özelliğin değiştiğini belirtmek için bir dize geçirmeliyiz. İle nameofdoğrudan mülkün adını kullanabiliriz. Bu büyük bir şey gibi görünmeyebilir. Ancak birileri mülkün adını değiştirdiğinde ne olacağını hayal edin Foo. Bir dize kullanırken ciltleme durur ancak derleyici sizi uyarmaz. Nameof kullanırken, ad ile hiçbir özellik / argüman yok derleyici hatası alırsınız Foo.

Bazı çerçevelerin, mülkün adını almak için bazı yansıma sihirleri kullandığını unutmayın, ancak şimdi bunun gerekli olmadığını anladık .


5
Bu geçerli bir yaklaşım olmakla birlikte, daha uygun (ve KURU) bir yaklaşım, [CallerMemberName]bu olayı oluşturmak için yeni bir yöntemin parametresindeki niteliği kullanmaktır .
Drew Noakes

1
Kabul ediyorum CallerMemberName de güzel, ama ayrı bir kullanım durumu, çünkü (dediğin gibi) sadece yöntemlerde kullanabilirsiniz. KURU gelince [CallerMemberName]string x = null, daha iyi olup olmadığından emin değilim nameof(Property). Özellik adının iki kez kullanıldığını söyleyebilirsiniz, ancak temelde argüman bir işleve iletilir. Gerçekten DRY ile kastedilen değil sanırım :).
Roy T.

Aslında bunu özelliklerde kullanabilirsiniz. Onlar da üye. Avantajı nameof, özellik ayarlayıcının özellik adını belirtmesi gerekmemesi, hataların kopyalanması / yapıştırılması olasılığını ortadan kaldırmasıdır.
Drew Noakes

4
Bu bir 'birlikte daha iyi' bir durum INotifyPropertyChangedkullanarak [CallerMemberNameAttribute]iken, değişikliği bildirimi temiz bir özellik setter gelen yükseltilmesine imkan verir nameofsözdizimi değişikliği bildirimi temiz kodunuzda farklı bir konumdan yükseltilmesine imkan verir.
Andrew Hanlon

9

En yaygın kullanım, giriş doğrulamasında olacaktır.

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

İlk durumda, par parametresinin adını değiştiren yöntemi yeniden düzenlerseniz , bunu ArgumentNullException içinde değiştirmeyi unutursunuz . İle NameOf Bu konuda endişe gerekmez.

Ayrıca bkz: nameof (C # ve Visual Basic Başvurusu)


7

ASP.NET Çekirdek MVC projesi kullanır nameofolarak AccountController.csve ManageController.csbirlikte RedirectToActionkontrol cihazı bir eylem referans yöntemi.

Misal:

return RedirectToAction(nameof(HomeController.Index), "Home");

Bu şu anlama gelir:

return RedirectToAction("Index", "Home");

ve yani 'Ev' denetleyicisi, içinde 'Dizin' eylem için kullanıcı alır alır /Home/Index.


Neden bütün domuzlara gitmiyorsun return RedirectToAction(nameof(HomeController.Index), nameof(HomeController).Substring(nameof(HomeController),0,nameof(HomeController).Length-"Controller".Length));?
Suncat2000

@ Suncat2000 çünkü bunlardan biri derleme yapılır, diğeri değil mi? :)
Dinerdo

6

Diğerlerinin de belirttiği gibi, nameofoperatör öğenin kaynak koduna verildiği adı ekler.

Bu dize yeniden düzenleme güvenli yapar çünkü bu yeniden düzenleme açısından gerçekten iyi bir fikir olduğunu eklemek istiyorum. Daha önce, aynı amaçla yansımayı kullanan, ancak çalışma zamanı performansı etkisi olan statik bir yöntem kullanıyordum. nameofOperatör bir çalışma zamanı performans etkisi vardır; derleme zamanında işini yapar. Eğer MSILkoda bir göz atarsanız, gömülü dizeyi bulacaksınız. Aşağıdaki yönteme ve sökülmüş koduna bakın.

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

Ancak, yazılımınızı gizlemeyi planlıyorsanız bu bir dezavantaj olabilir. Gizleme sonrasında gömülü dize artık öğenin adıyla eşleşmeyebilir. Bu metne dayanan mekanizmalar kırılacaktır. Bunlara örnekler, bunlarla sınırlı olmamak üzere aşağıdakileri içerir: Yansıma, NotifyPropertyChanged ...

Çalışma zamanı sırasında adın belirlenmesi biraz performans gerektirir, ancak gizleme için güvenlidir. Ne şaşkınlık ne de planlanmışsa nameofoperatörün kullanılmasını tavsiye ederim .


5

Kodunuzda bir değişken kullandığınızı ve değişkenin adını almanız gerektiğini düşünün ve diyelim ki yazdırın, şunu kullanmalısınız:

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

Ve sonra birisi kodu yeniden düzenler ve "myVar" için başka bir ad kullanırsa, kodunuzdaki dize değerini izlemesi ve buna göre chenge etmesi gerekir.

Bunun yerine

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

Bu otomatik olarak refactor yardımcı olacaktır!


Ben kaynak kodu gösterimi Type, ve değeri içeren her parametre için bir tuples bir dizi geçirecek özel bir değişken parametre sözdizimi olsaydı . Bu, kod çağırma günlükleme yöntemlerinin fazlalığı ortadan kaldırmasını mümkün kılacaktır.
supercat

5

MSDN makalesinde , diğerleri arasında MVC yönlendirmesi (benim için konsepti gerçekten tıklayan örnek) listelenmektedir. (Biçimlendirilmiş) açıklama paragrafında şunlar bulunur:

  • Koddaki hataları bildirirken,
  • Model-view-controller (MVC) bağlantılarını bağlamak,
  • ateşleme özelliği değişti olayları, vb.

genellikle bir yöntemin dize adını yakalamak istersiniz . Nameof kullanımı , tanımları yeniden adlandırırken kodunuzun geçerli kalmasına yardımcı olur .

Önce , kod öğelerini yeniden adlandırırken gevrek olan tanımlara başvurmak için dize değişmezlerini kullanmak zorunda kaldınız çünkü araçlar bu dize değişmez değerlerini kontrol etmeyi bilmiyor.

Kabul edilen / en çok puan alan cevaplar zaten birkaç mükemmel somut örnek veriyor.


3

nameofOperatörün amacı , eserlerin kaynak adını vermektir.

Genellikle kaynak adı meta veri adıyla aynı addır:

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

Ancak bu her zaman böyle olmayabilir:

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

Veya:

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

Buna verdiğim bir kullanım, kaynakları adlandırmaktır:

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

Gerçek şu ki, bu durumda, kaynaklara erişmek için oluşturulan özelliklere bile ihtiyacım yoktu, ama şimdi kaynakların var olup olmadığını kontrol etmek için bir derleme zamanım var.


0

nameofAnahtar kelime kullanımından biri Bindingwpf'de programlı olarak ayarlamak içindir .

sete Bindingsete zorunda Pathdize ile ve ilenameof anahtar kelime ile, Refactor seçeneğini kullanmak mümkündür.

Örneğin, cihazınızda IsEnablebağımlılık özelliği varsa UserControlve bunu alanınızdaki IsEnablebazı kullanıcılara bağlamak istiyorsanız, şu iki kodu kullanabilirsiniz:CheckBoxUserControl

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

ve

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

Açıkçası ilk kod refactor olamaz ama secend bir ...


0

Daha önce böyle bir şey kullanıyorduk:

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

Sebep - zaman güvenliğini derleyin. Hiç kimse sessizce özelliği yeniden adlandıramaz ve kod mantığını bozamaz. Şimdi nameof () kullanabiliriz.


0

ASP.Net MVC kullandığınızda avantajı vardır. Görünümde bir denetim oluşturmak için HTML yardımcısını kullandığınızda, html girdisinin ad özelliğinde özellik adlarını kullanır:

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

Böyle bir şey yapar:

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

Şimdi, mülkünüzü Validate yönteminde doğrulamanız gerekiyorsa, bunu yapabilirsiniz:

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

Yeniden düzenleme araçlarını kullanarak mülkünüzü yeniden adlandırırsanız, doğrulama işleminiz bozulmaz.


0

Diğer bir kullanım durumu nameofsekme sayfalarını kontrol etmektir, dizini kontrol etmek yerine sekmelerin sayfalarını aşağıdaki gibi kontrol edebilirsiniz Name:

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

Daha az dağınık :)


0

Uygulamalarımdaki nameofçok uzun ve karmaşık SQL ifadelerinin okunabilirliğini artırdığını görüyorum . Değişkenleri o dizelerden farklı kılar ve SQL ifadelerinizde değişkenlerin nerede kullanıldığını bulma işinizi ortadan kaldırır.

public bool IsFooAFoo(string foo, string bar)
{
    var aVeryLongAndComplexQuery = $@"SELECT yada, yada
    -- long query in here
    WHERE fooColumn = @{nameof(foo)}
    AND barColumn = @{nameof(bar)}
    -- long query here";


    SqlParameter[] parameters = {
        new SqlParameter(nameof(foo), SqlDBType.VarChar, 10){ Value = foo },
        new SqlParameter(nameof(bar), SqlDBType.VarChar, 10){ Value = bar },
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.