c# - 为什么不能使用 is 运算符来区分 bool 和 Nullable?
问题描述
我遇到了这个问题,很好奇为什么不能使用is
操作符来区分bool
and Nullable<bool>
?例子;
void Main()
{
bool theBool = false;
Nullable<bool> theNullableBoolThatsFalse = false;
Nullable<bool> theNullableBoolThatsNull = null;
void WhatIsIt(object value)
{
if(value is bool)
Console.WriteLine(" It's a bool!");
if(value is Nullable<bool>)
Console.WriteLine(" It's a Nullable<bool>!");
if(value is null)
Console.WriteLine(" It's a null!");
}
Console.WriteLine("Considering theBool:");
WhatIsIt(theBool);
Console.WriteLine("Considering theNullableBoolThatsFalse:");
WhatIsIt(theNullableBoolThatsFalse);
Console.WriteLine("Considering theNullableBoolThatsNull:");
WhatIsIt(theNullableBoolThatsNull);
}
呼唤Main()
给予;
Considering theBool:
It's a bool!
It's a Nullable<bool>!
Considering theNullableBoolThatsFalse:
It's a bool!
It's a Nullable<bool>!
Considering theNullableBoolThatsNull:
It's a null!
我希望;
Considering theBool:
It's a bool!
Considering theNullableBoolThatsFalse:
It's a Nullable<bool>!
Considering theNullableBoolThatsNull:
It's a null!
为什么两者都bool
相互Nullable<bool>
匹配?
我尝试了什么;
- 我已经查阅了有关
Nullable
、is
和switch
模式匹配的文档。 - 我认为这可能与将值传递给方法时的拆箱有关?
我认为它可能是独一无二的,Nullable
因为我没有遇到其他泛型类型的相同问题。例如;
void Main()
{
bool theBool = false;
List<bool> theListOfBool= new List<bool>();
void WhatIsIt(object value)
{
if(value is bool)
Console.WriteLine(" It's a bool!");
if(value is List<bool>)
Console.WriteLine(" It's a List<bool>!");
}
Console.WriteLine("Considering theBool:");
WhatIsIt(theBool);
Console.WriteLine("Considering theListOfBool:");
WhatIsIt(theListOfBool);
}
给;
Considering theBool:
It's a bool!
Considering theListOfBool:
It's a List<bool>
我不是要解决问题。只是对它为什么以这种方式工作感兴趣。
到目前为止的答案表明它implicit
和explicit
转换导致了这种行为,但我无法用下面的例子进行复制;
class A
{
public static implicit operator A(B value) => new A();
public static explicit operator B(A value) => new B();
}
class B
{
public static implicit operator A(B value) => new A();
public static explicit operator B(A value) => new B();
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
void WhatIsIt(object value)
{
if (value is A)
Console.WriteLine(" It's a A!");
if (value is B)
Console.WriteLine(" It's a B!");
}
Console.WriteLine("Considering a;");
WhatIsIt(a);
Console.WriteLine("Considering b;");
WhatIsIt(b);
}
给;
Considering a;
It's a A!
Considering b;
It's a B!
文档is
说:
它只考虑引用转换、装箱转换和拆箱转换;它不考虑用户定义的转换或由类型的隐式和显式运算符定义的转换。以下示例生成警告,因为转换的结果在编译时是已知的。请注意,从 int 到 long 和 double 的转换的 is 表达式返回 false,因为这些转换由隐式运算符处理。
参考转换、装箱转换和拆箱转换是框架决定的吗?
解决方案
传递给您的方法时的原因bool
和Nullable<bool>
行为相同是因为每当您装箱时,Nullable<T>
它实际上并没有装箱可空值,而是解开可空值并将其装箱。如果可为空的值为 null ,那么您最终会得到 just null
,而不是装箱的Nullable<T>
where HasValue
is false
。
如果你装箱一个非空值,它只会装箱Value
. Nullable<T>
所以从角度来看WhatIsIt
,前两个调用实际上是无法区分的,因为传入的是完全相同的值。
这只是留下了为什么两个 is
检查都返回的问题true
,即使在这两种情况下传入的都是一个装箱的布尔值,而不是一个Nullable<T>
. C# 语言规范第 7.10.10 节回答了这一点:
如果 T 是可空类型,则如果 D 是 T 的基础类型,则结果为真。
在这种情况下,这是考虑E is T
并D
在前面定义为E
where 的计算值:
如果 E 的类型是可空类型,则 D 是该可空类型的基础类型。
这意味着该is
运算符被明确定义为将可空类型视为等同于它们的基础类型,无论您如何混合和匹配正在检查的实际值以及您使用可空值检查的类型和该可空值的基础类型。
推荐阅读
- python - 如何使用python编辑htm文件中的表头?
- python - pymongo 使用 find() 查询数组总是失败
- mongodb - 在 mongoDB 中,函数 AddToSet 添加重复项
- c - linux内核移植中的问题,卡在paging_init函数中
- android - PeriodicWorkRequest 初始延迟的任何方式
- java - Java 8 谓词
- swift - PromiseKit 6中的重试机制,通过在recover中进行额外调用
- android - 我们现在应该使用 Java 8 进行 Android 开发吗?
- sql-server - 架构名称在 MSSQL 中不起作用
- android - 在android默认CalendarView中禁用所有过去的日期?