名称与类型之间的区别
本文关键字:区别 之间 类型 | 更新日期: 2023-09-27 18:21:26
如果我错了,请纠正我,但要做类似的事情
var typeOfName = typeof(Foo).Name;
和
var nameOfName = nameof(Foo);
应该给你完全相同的输出。根据该消息来源,可以理解的原因之一: https://msdn.microsoft.com/en-us/library/dn986596.aspx
"使用 nameof 有助于在重命名定义时保持代码有效">
如果你想把类实例作为字符串获取,就不可能做这样的事情:
var fooInstance = new Foo();
var nameOfName = nameof(fooInstance);
但是,您可以执行以下操作:
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
var typeOfName2 = GetName(new { fooInstance });
在这两种情况下(typeof
和nameof
(,重构都是可能的,所以我看不出任何其他理由来重新发明另一个更高级别的关键字,例如nameof
,以执行已经存在的东西。它们之间有什么我不清楚的差异吗?
最后,如果有人能指出我的参考来源以查看nameof
的实施,我将不胜感激。它使用反射吗?
更新 1:取自这里
nameof
显然与声明字符串变量一样有效。没有反射或任何东西!
var firstname = "Gigi";
var varname = nameof(firstname);
Console.WriteLine(varname); // Prints "firstname" to the console
当您签出生成的 MSIL 时,您将看到它等效于字符串声明,因为对字符串的对象引用使用 ldstr 运算符推送到堆栈:
IL_0001: ldstr "Gigi"
IL_0006: stloc.0
IL_0007: ldstr "firstname"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: call void [mscorlib]System.Console::WriteLine(string)
两个原因:
nameof
转换为编译时常量。 typeof(...).Name
需要一点反思。它并不太贵,但在某些情况下可能会造成伤害。
其次,它用于类型名称以外的其他内容。例如,参数:
void SomeMethod(int myArgument)
{
Debug.WriteLine(nameof(myArgument));
}
您还可以获取班级成员甚至当地人的名称。不用说,这对于调试信息非常有用。这也是在解析表达式树时实现不太脆弱的反射的方法之一(可悲的是,在我使用它的项目中,我们仍然停留在带有 C# 5 的 .NET 4.0 上 - 它会为我节省一些技巧(。
为了澄清一些困惑,nameof
不是一个函数,typeof
也不是。它是一个编译时运算符,它总是在编译时计算(尽管很明显,泛型在时间上将"编译时"移动得更远(。
下面是使用 BenchmarkDotNet 进行的基准测试
// * Summary *
Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Windows
Processor=?, ProcessorCount=8
Frequency=2740584 ticks, Resolution=364.8857 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003133
Type=GetNameBenchmark Mode=Throughput LaunchCount=2
WarmupCount=10 TargetCount=200
Method | Median | StdDev |
----------- |----------- |---------- |
TypeOf | 16.0348 ns | 0.7896 ns |
NameOf | 0.0005 ns | 0.0147 ns |
使用反射生成字符串是可能的,但不是很优雅,并不总是可能的。 例如,不能在沙盒代码中使用反射。 而且你不能在局部变量上使用它。 而且很贵。
nameof
运算符在编译时工作。 编译器在分析代码时已经知道名称。 所以可以简单地生成字符串文字。 非常快,不可能更快,并且没有运行时限制。
它们之间有几个区别,但它们主要是背后的实际原因。示例 1:
写这样的东西更优雅
switch (e.ArgumentPropertyName)
{
case nameof(aProperty):
break;
case "anotherProperty":
break;
}
尝试重构anotherProperty
类型并砰! nameof
将反映更改,"anotherProperty"
将静默传递,您的代码将永远不会在该 case 语句中执行。
示例 2:
enum MetalEnum { Gold = 1, Silver = 2, ... }
哪一个更好?
Console.WriteLine(MetalEnum.Gold.ToString()); // finds the name at runtime (slower)
或
Console.WriteLine(nameof(MetalEnum.Gold)); // compile time (faster)
例3:
最后,你还记得写这样的东西有多丑
吗PropertyChanged(this, new PropertyChangedEventArgs("Foo"));
现在你可以写得很漂亮,如下所示:
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));
Typeof 返回 Type 对象。它通常用作参数或变量或字段。typeof 运算符是获取 Type 指针的表达式的一部分。
class Program
{
static Type _type = typeof(char); // Store Type as field.
static void Main()
{
Console.WriteLine(_type); // Value type pointer
Console.WriteLine(typeof(int)); // Value type
Console.WriteLine(typeof(byte)); // Value type
Console.WriteLine(typeof(Stream)); // Class type
Console.WriteLine(typeof(TextWriter)); // Class type
Console.WriteLine(typeof(Array)); // Class type
Console.WriteLine(typeof(int[])); // Array reference type
}
}
输出
System.Char
System.Int32
System.Byte
System.IO.Stream
System.IO.TextWriter
System.Array
System.Int32[]
同时,Nameof 返回一个带有变量名称的字符串。它在编译时工作。它是一种特殊的编译器功能,可简化某些程序。
int size=100;
Console.WriteLine(nameof(size));
输出:大小
根据文档:
用于获取变量、类型或成员的简单(非限定(字符串名称。
。
nameof 的参数必须是简单名称、限定名称、成员访问权限、具有指定成员的基本访问权限或具有指定成员的此访问权限。参数表达式标识代码定义,但从不计算它。
由于参数需要在语法上是表达式,因此有许多不允许列出的内容没有用。以下值得一提的是会产生错误:预定义类型(例如,int 或 void(、可为空的类型 (
Point?
(、数组类型 (Customer[,]
(、指针类型 (Buffer*
(、限定别名 (A::B
( 和未绑定泛型类型 (Dictionary<,>
(、预处理符号 (DEBUG
( 和标签 (loop:
(。
nameof 获取的简单名称是源名称,而不是元数据名称。
所以,这段代码:
using Integer = System.Int32;
var s = "a string";
Console.WriteLine(nameof(s));
Console.WriteLine(nameof(Integer));
Console.WriteLine(nameof(System.Int32));
void M<T>() { Console.WriteLine(nameof(T)); }
M<int>();
M<string>();
将打印:
s
Integer
Int32
T
T
Typeof 返回 Type 对象。它通常用作参数或变量或字段。typeof 运算符是获取 Type 指针的表达式的一部分。
同时,Nameof 返回一个带有变量名称的字符串。它在编译时工作。它是一种特殊的编译器功能,可简化某些程序。