c# - 如果System.Double将常量字段 "NaN"初始化为double.NaN,是不是意味着 "Double"和 "double"指的不是同一个类型?

标签 c# .net il disassembly

在Visual Studio C#编辑器中,当你右击关键字“double”或标识符“Double”并选择“Go to Definition”时,VS会告诉你“NaN”被声明和初始化如下:

 public const double NaN = 0.0 / 0.0;
 //public const double NegativeInfinity = -1.0 / 0.0;
 //public const double PositiveInfinity = 1.0 / 0.0;

但是,从 mscorlib.dll 反汇编的 System.Double 的源代码讲述了一个不同的故事:

public const double NaN = double.NaN;
//public const double NegativeInfinity = double.NegativeInfinity;
//public const double PositiveInfinity = double.PositiveInfinity;

当然,.NET 不会让您使用对自身的引用(循环定义)或对自身的引用来初始化常量字段(不允许使用对实例字段的引用来初始化实例字段) ,虽然可以使用对自身的引用来初始化静态字段,但显然这里不是这种情况。

现在,大多数 .NET 书籍教导的第一件事是标识符“Double”和关键字“double”都指代相同的类型(对于 int 和 Int32、string 和 String 等都是相同的),并且任何怀疑这一点的人只要快速浏览一下 IL 就足以证明这一点。

考虑到这一点,为什么 System.Double 类型可以将 double 类型的常量字段初始化为自身?是不是意味着,

...适用于纯 .NET 程序员编写的代码的规则不适用于内部 .NET 代码? ...反汇编器弄错了吗? ..."double"和 "double"真的不是同一种类型吗?

最佳答案

double是 C# 关键字 - System.Double 类型的别名.您的假设是 mscorlib.dll是用 C# 编写的。另外,反编译器是错误的。 NaN 的常量是否有一个明确的 double 值 - 反编译器只是希望您希望将该常量视为 double.NaN而不是 double.NaN (您可能甚至不知道)。

在已编译的 IL 中(在 dll 内部),常量不按名称引用。这是一件非常重要的事情。如果你这样做,例如:

const int Zero = 0;

Console.Write(Zero);

代码(不是声明)将编译为相同

Console.Write(0);

理解这一点非常重要,因为常量值是在编译时解析的,而不是运行时。如果您从引用库中获取常量,并且该引用库中常量的值发生变化,您的代码中将保留旧值,直到您针对新版本重新编译。

如果你需要一个可以在库版本之间改变的“常量”,你最好使用静态属性,例如:

static int Zero { get { return 0; } }

那么引用的其实是属性,而不是它的值。

C# 中的默认参数存在相同的行为。它们也在编译时解决,所以它们并没有完全使构造函数/方法重载过时:)

想象一个方法:

public void DoSomething(bool isSafe = true);

一切都很好。但是随后您决定默认行为应该是不安全的,而不是安全的。或者更糟的是,您更改了 bool 值的含义(当您使用像 flag 这样的参数名称时,这是一个严重的问题 :))。所以你改变定义

public void DoSomething(bool isSafe = false);

所有将您的方法称为 DoSomething() 的人将使用参数的旧值 true 调用它.直到他们重新编译。如果您不了解何时解析默认参数,这可能会非常令人沮丧且难以调试 :)

回到别名关键字 - 在某些情况下,两者并不相同。然而,这是因为编译器解析某些表达式的方式。最好的例子是 enum关键词:

enum MyEnum : byte {} // Valid, an enum with an underlying type of byte.

enum MyEnum2 : System.Byte {} // Invalid, unexpected token. 
// "Type byte, sbyte, short, ushort, int, uint, long, or ulong expected"

既然我们已经在谈论枚举,是的,它们有同样的问题。它们由它们的基础“数字”表示。如果你改变它,旧的数字突然指向一个不同的“枚举值”,反之亦然 - 如果你创建或使用一些 API,这又是一个大问题 :)

关于c# - 如果System.Double将常量字段 "NaN"初始化为double.NaN,是不是意味着 "Double"和 "double"指的不是同一个类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21779725/

相关文章:

c# - 为什么类中定义的委托(delegate)不能被类对象访问

c# - 使用 Parallel.For 时出现不可预测的结果

c# - 在 Visual Studio C# Express 2010 中调试 Nunit 测试

c# - HostBuilder.Build() 返回的 IHost 实例属于哪个类?

.net - 为什么私有(private)常量存储在 .NET 程序集中?

c# - Debug.Assert 是否在 Release模式下生成 IL?

c# - DbContextTransaction 关于回滚的说明

c# - EF Linq to Entities 在实体集上调用 ToList() 生成包含多个左外连接的 SQL 命令

.net - 在 Linux/ARM 上使用 pinvoke 和 C 函数回调的 F# 委托(delegate)

c# - void 方法在最基本的情况下是否比返回值的方法更快/更少开销?