【c#操作符】-nameof⽤法
最重要的是nameof不会影响性能!
nameof有什么⽤?主要⽤解决类成员名做参数替代成员们的字符串做参数,如下:
using  System;
namespace csharp6
{
internal class Program
{
private static void Main(string[] args)
{
if (args==null)
{
throw new ArgumentNullException("args");//旧的写法变量名的字符串做参数
//throw new ArgumentNullException(nameOf(args));//新的写法避免了args变量名更改后,忘记更改字符串"args",因为字符串编译器是不错提⽰错误的
} } } }
这样⾮常有利于后期项⽬维护,⽐如我们在使⽤MVC开发时候,后端返回到某个视图,我们平时喜欢写字符串的形式,如果项⽬越来越⼤,后期突然哪个控制器或者动作不⽤了,使⽤字符串的形式维护起来就⾮常⿇烦,⽤nameof就可以很好的解决,最重要的是不会影响性能!
nameof 运算符
nameof是C#6新增的⼀个关键字运算符,主要作⽤是⽅便获取类型、成员和变量的简单字符串名称(⾮完全限定名),意义在于避免我们在代码中写下固定的⼀些字符串,这些固定的字符串在后续维护代码时是⼀个很繁琐的事情。⽐如上⾯的代码改写后:
using  System;
namespace csharp6
{
internal class Program
{
private static void Main(string[] args)
{
if (args==null)
{
throw new ArgumentNullException(nameof(args));
}
}
}
}
我们把固定的 "args" 替换成等价的 nameof(args) 。按照惯例,贴出来两种⽅式的代码的IL。
"args"⽅式的IL代码
.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size      22 (0x16)
.maxstack  2
.locals init ([0] bool V_0)
IL_0000:  nop
IL_0001:  ldarg.0
IL_0002:  ldnull
IL_0003:  ceq
IL_0005:  stloc.0
IL_0006:  ldloc.0
IL_0007:  brfalse.s  IL_0015
IL_0009:  nop
IL_000a:  ldstr      "args"
IL_000f:  newobj    instance void [mscorlib]System.ArgumentNullException::.ctor(string)
IL_0014:  throw
IL_0015:  ret
} // end of method Program::Main
nameof(args)⽅式的IL代码:
.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size      22 (0x16)
.maxstack  2
.locals init ([0] bool V_0)
IL_0000:  nop
IL_0001:  ldarg.0
IL_0002:  ldnull
IL_0003:  ceq
IL_0005:  stloc.0
IL_0006:  ldloc.0
IL_0007:  brfalse.s  IL_0015
IL_0009:  nop
IL_000a:  ldstr      "args"
IL_000f:  newobj    instance void [mscorlib]System.ArgumentNullException::.ctor(string)
IL_0014:  throw
IL_0015:  ret
} // end of method Program::Main
⼀样⼀样的,我是没看出来有任何的差异,,,so,这个运算符也是⼀个编译器层⾯提供的语法糖,编译后就没有nameof的影⼦了。3. nameof 注意事项
nameof可以⽤于获取具名表达式的当前名字的简单字符串表⽰(⾮完全限定名)。注意当前名字这个限定,⽐如下⾯这个例⼦,你觉得会输出什么结果?
using static System.Console;
using CC = System.ConsoleColor;
namespace csharp6
{
internal class Program
{
private static void Main()
{
WriteLine(nameof(CC));//CC
WriteLine(nameof(System.ConsoleColor));//ConsoleColor
}
}
}
第⼀个语句输出"CC",因为它是当前的名字,虽然是指向System.ConsoleColor枚举的别名,但是由于CC是当前的名字,那么nameof运算符的结果就是"CC"。
第⼆个语句输出了"ConsoleColor",因为它是System.ConsoleColor的简单字符串表⽰,⽽⾮取得它的完全限定名,如果想取
得"System.ConsoleColor",那么请使⽤ typeof(System.ConsoleColor).FullName 。再⽐如微软给的例
⼦: nameof(person.Address.ZipCode) ,结果是"ZipCode"。
以上内容来⾃:
以前我们使⽤的是这样的:
// 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)
{
...
}
原因-编译时间安全。没有⼈可以默默地重命名属性并破坏代码逻辑。现在我们可以使⽤nameof()了。
如果要重⽤属性名称,例如在基于属性名称引发异常或处理PropertyChanged事件时,该怎么办?在很多情况下,您都希望使⽤属性名称。
举个例⼦:
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break; }
// opposed to
case "SomeOtherProperty":
{ break; }
}
在第⼀种情况下,重命名SomeProperty也将更改属性的名称,否则将中断编译。最后⼀种情况没有。
这是保持代码编译和消除错误(排序)的⼀种⾮常有⽤的⽅法。
(为什么infoof没能做到,⽽nameof却做到了)
对于ArgumentException及其派⽣类确实⾮常有⽤:
public string DoSomething(string input)
{
if(input == null)
{
throw new ArgumentNullException(nameof(input));
}
...
现在,如果有⼈重构input参数的名称,该异常也将保持最新状态。
在某些以前必须使⽤反射来获取属性或参数名称的地⽅,它也很有⽤。
在您的⽰例中,nameof(T)获取类型参数的名称-这也可能有⽤:
throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");
nameof另⼀种⽤法是⽤于枚举-通常,如果您想要使⽤.ToString()的枚举的字符串名称:
enum MyEnum { ... FooBar = 7 ... }
Console.WriteLine(MyEnum.FooBar.ToString());
> "FooBar"
由于.Net保留枚举值(即7)并在运⾏时查名称,因此这实际上相对较慢。
⽽是使⽤nameof:
Console.WriteLine(nameof(MyEnum.FooBar))
> "FooBar"
现在,.Net在编译时⽤字符串替换枚举名称。
还有另⼀个⽤途是⽤于INotifyPropertyChanged和⽇志记录-在两种情况下,您都希望将要调⽤的成员的名称传递给另⼀个⽅法:// Property with notify of change
public int Foo
{
get { return this.foo; }
set
{
this.foo = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
}
}
要么...
// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
Log(nameof(DoSomething), "");
}
我能想到的最常见的⽤例是使⽤INotifyPropertyChanged接⼝时。(基本上,与WPF和绑定有关的所有内容都使⽤此接⼝)
看⼀下这个例⼦:
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)));
}
}
}
如您所见,我们必须传递⼀个字符串以指⽰哪个属性已更改。使⽤nameof我们可以直接使⽤属性的名称。这似乎没什么⼤不了的。但是想像⼀下当有⼈更改属性Foo的名称时会发⽣什么。使⽤字符串时,绑定将停⽌⼯作,但编译器不会警告您。使⽤nameof时,会出现⼀个编译器错误,即没有名称为Foo属性/参数。
请注意,某些框架使⽤⼀些反射魔术来获取属性的名称,但是现在我们有了nameof,它不再是必需的。
最常见的⽤法是在输⼊验证中,例如
//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));
}
在第⼀种情况下,如果重构更改par 参数名称的⽅法,则可能会忘记在ArgumentNullException中进⾏更改。使⽤nameof,您不必担⼼。
另请参见:
考虑到您在代码中使⽤了变量,并且需要获取变量的名称并可以说将其打印出来,因此您必须使⽤
int myVar = 10;
print("myVar" + " value is " + String());
然后如果有⼈重构代码并为“ myVar”使⽤另⼀个名称,则他/她将必须注意代码中的字符串值并相应地对其进⾏处理。
相反,如果您有
print(nameof(myVar) + " value is " + String());
这将有助于⾃动重构!
nameof关键字的⽤法之⼀是⽤于以编程⽅式在wpf中设置Binding。
要设置Binding您必须使⽤字符串和nameof关键字设置Path,可以使⽤Refactor选项。
例如,如果您在UserControl具有IsEnable依赖项属性,并且要将其绑定到UserControl中某些CheckBox IsEnable,则可以使⽤以下两个代码:
CheckBox chk = new CheckBox();
Binding bnd = new Binding ("IsEnable") { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
CheckBox chk = new CheckBox();
Binding bnd = new Binding (nameof (IsEnable)) { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
很明显,第⼀个代码⽆法重构,⽽第⼆个代码可以重构。
nameof运算符的⽬的是提供⼯件的源名称。
通常,源名称与元数据名称相同:
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));
}
}
但这并⾮总是如此:
using i = System.Int32;
...
Console.WriteLine(nameof(i)); // prints "i"
要么:
public static string Extension<T>(this T t)
{
return nameof(T); returns "T"
}
我⼀直给它的⼀种⽤途是命名资源:
[Display(
ResourceType = typeof(Resources),typeof的用法
Name = nameof(Resources.Title_Name),
ShortName = nameof(Resources.Title_ShortName),
Description = nameof(Resources.Title_Description),
Prompt = nameof(Resources.Title_Prompt))]
事实是,在这种情况下,我什⾄不需要⽣成的属性来访问资源,但是现在有了编译时检查资源是否存在。
C#6.0的 nameof 功能变得很⽅便的另⼀个⽤例 -考虑像这样的库,它使DB检索更加容易。尽管这是⼀个很棒的库,但是您需要在查询中对属性/字段名称进⾏硬编码。这意味着如果您决定重命名属性/字段,则很可能会忘记更新查询以使⽤新的字段名。使⽤字符串插值和nameof功能,代码变得更加易于维护和类型安全。
从链接中给出的⽰例
没有名字
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
与nameof
var dog = connection.Query<Dog>($"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id", new { Age = (int?)null, Id = guid });
以上内容来⾃:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。