问题的第1部分:在下面的代码中,为什么value == default编译良好,而其他替代方法却没有?
bool MyEqual<T>(T value)
{
T value2 = default;
if (value == value2) // Error: Operator '==' cannot be applied to operands of type 'T' and 'T'
return true;
if (value == default(T)) // Error: Operator '==' cannot be applied to operands of type 'T' and 'T'
return true;
if (value == default) // No error
return true;
return false;
}
Run Code Online (Sandbox Code Playgroud)
问题的第2部分:在下面的代码中,为什么前三幅显示而后三幅false显示true?
bool MyEqual<T>(T value)
{
if (value == default)
return true;
return false;
}
Console.WriteLine($"{MyEqual<int>(0)}"); // False
Console.WriteLine($"{MyEqual<int>(default)}"); // False
Console.WriteLine($"{MyEqual<int>(default(int))}"); // False
Console.WriteLine($"{MyEqual<string>(null)}"); // True
Console.WriteLine($"{MyEqual<string>(default)}"); // True
Console.WriteLine($"{MyEqual<string>(default(string))}"); // True
Run Code Online (Sandbox Code Playgroud)
概括起来:表达式的行为是value == default什么?
编辑:请不要将其标记为该另一个问题的重复项,因为那是另一个不同的情况,value == default(T)而不是value == default:
default(object)是什么?用C#做?
另外,我的问题是关于使用“ ==”运算符时的奇怪行为,正如我上面解释的那样。
在==操作数类型是泛型参数的上下文中,value == default似乎发出等效的 IL 到value == null,它总是评估false为不可为空的值类型操作数。
鉴于:
static bool IsDefault<T>(T value) => value == default;
static bool IsNull<T>(T value) => value == null;
Run Code Online (Sandbox Code Playgroud)
我们得到 IL:
.method private hidebysig static
bool IsDefault<T> (
!!T 'value'
) cil managed
{
// Method begins at RVA 0x2050
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ldnull
IL_0007: ceq
IL_0009: ret
} // end of method C::IsDefault
.method private hidebysig static
bool IsNull<T> (
!!T 'value'
) cil managed
{
// Method begins at RVA 0x205b
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ldnull
IL_0007: ceq
IL_0009: ret
} // end of method C::IsNull
Run Code Online (Sandbox Code Playgroud)
你可以原谅你发现这令人惊讶。这意味着,例如,当T绑定到不可为空的值类型(如 )时int,表达式的value == default计算false结果为0。与此相反,内联表达0 == default,其评估对true。
Console.WriteLine(IsDefault<int>(0)); // False
Console.WriteLine(IsNull<int>(0)); // False
Console.WriteLine(IsDefault<int?>(null)); // True
Console.WriteLine(IsNull<int?>(null)); // True
Console.WriteLine(IsDefault<int?>(0)); // False
Console.WriteLine(IsNull<int?>(0)); // False
Run Code Online (Sandbox Code Playgroud)
因此,显然,对于value不受约束的泛型参数类型的 a,表达式value == default和value == default(T)是不等价的。如果合法,后者将(大概)评估true值是否为空、假或“归零”值类型(例如,所有组成值也是默认值的值类型)。
至于为什么value == default(T)不编译,答案很简单:编译器不知道如何评估==编译时未知的类型。如果您要添加约束where T : class,那么编译器至少可以执行引用比较。但是只要T可能是原始类型、自定义值类型或引用类型,编译器就不知道如何发出比较。给定的实例化的正确实现T可能是内置的原始比较、op_Equality重载或引用比较。更重要的是,它可能根本不受支持。 真正造成问题的是最后一种可能性。
虽然 C#/.NET 工程师可以想出一种方法,将正确比较的计算推迟到运行时,但这也意味着在运算符根本不适用的情况下,将编译时错误换成运行时异常,而我不要觉得那笔交易很吸引人
| 归档时间: |
|
| 查看次数: |
286 次 |
| 最近记录: |