繁体   English   中英

为什么不能使用is运算符来区分bool和Nullable <bool> ?

[英]Why is it not possible to use the is operator to discern between bool and Nullable<bool>?

我遇到了这个并且很好奇为什么不能使用is运算符来区分boolNullable<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!

为什么boolNullable<bool>都相互匹配?

我试过了什么;

  • 我已经咨询了Nullable的文档, isswitch和模式匹配。
  • 我认为这可能与传递给方法时的值的拆箱有关?

我认为它可能是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>

我不打算解决问题。 只是感兴趣为什么它这样工作。

到目前为止,答案表明它是implicitexplicit转换导致此行为,但我无法使用以下示例进行复制;

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,因为这些转换由隐式运算符处理。

框架决定参考转换,装箱转换和拆箱转换吗?

boolNullable<bool>在传递给你的方法时表现相同的原因是因为每当你装入一个Nullable<T>它实际上并没有包装可空值,而是展开了可空和值的值。 如果可空值为null,则最后只使用null ,而不是装箱的Nullable<T> ,其中HasValuefalse

如果你框一个非空值,它只会框中的Value的的Nullable<T> 因此,从WhatIsIt的角度来看,前两个调用实际上是无法区分的 ,因为传递完全相同的值

这就留下了为什么两个 is检查返回true ,即使在两种情况下传入的都是盒装布尔值,而不是Nullable<T> 这可以通过C#语言规范第7.10.10节来回答:

如果T是可空类型,如果D是T的基础类型,则结果为真。

在这种情况下,这是考虑E is TD先前定义为E的计算值,其中:

如果E的类型是可空类型,则D是该可空类型的基础类型。

这意味着is运算符被明确定义为将可空类型视为等效于它们的基础类型,无论您如何混合和匹配正在检查的实际值以及您使用可空值和可空的底层类型检查的类型。

false可以安全地转换为boolbool? 因为它们之间有一个隐式的转换操作符。

另一方面null不能转换为bool ,这就是为什么null is bool返回false

is运算符不会(并且不能)关心如何声明变量 - 如果有的话。 它仅指示运行时提供的类型。 你也可以这样写:

WhatIsIt(false)

您希望这种方法在这里表现如何? 它只是尝试将值转换为两种类型 - 它可以 - 然后为两者返回true。

为什么它对其他泛型不起作用只是因为在最通用的类​​型和它们的类型参数之间没有隐式转换。 因此以下不起作用:

string myString = new List<string>();

Nullable<T>类实现了隐式显式运算符,这些运算符在开箱即用的情况下使用,请查看文档

以下是源代码的摘录:

[System.Runtime.Versioning.NonVersionable]
public static implicit operator Nullable<T>(T value) {
    return new Nullable<T>(value);
}

[System.Runtime.Versioning.NonVersionable]
public static explicit operator T(Nullable<T> value) {
    return value.Value;
}

当你申报时

Nullable<bool> theNullableBoolThatsFalse = false;

theNullableBoolThatsFalse可以保存'true','false'或'null',类似于theNullableBoolThatsNull可以保存布尔值和Null。 当你指定Null时,它完全变为null,不能是任何其他类型。 它不涉及任何对象。 有关Nullable的信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM