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

时间:2019-01-10 12:04:34

标签: c# types boxing

我碰到了这一点,并对为什么无法使用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>彼此匹配?

我尝试了什么;

  • 我已经咨询了Nullableisswitch和模式匹配的文档。
  • 我认为这可能与值的unboxing传递给方法有关?

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

参考转换,装箱转换和拆箱转换是否由框架决定?

4 个答案:

答案 0 :(得分:8)

boolNullable<bool>在传递给您的方法时表现相同的原因是,每当您装箱Nullable<T>时,它实际上并未装箱可为空的值,而是解开了该值nullable和box的值。如果可为空的值为null,那么您最终只会得到null,而不是装在方框中的Nullable<T>,其中HasValuefalse

如果您将非null值装箱,它将只装Value中的Nullable<T>。因此,从WhatIsIt的角度来看,前两个调用是在字面上无法区分的,因为传入的是完全相同的值

这只是一个问题,为什么 is会返回true,即使在两种情况下传入的都是带框的布尔值,而不是{ {1}}。 C#语言规范的第7.10.10节对此做了回答:

  

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

在这种情况下,这是在考虑Nullable<T>,并且E is T早先被定义为D的计算值,其中:

  

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

这意味着E运算符被专门定义为将可空类型视为等同于其基础类型,无论您如何混合和匹配要检查的实际值和类型您正在检查可为空的值以及该可为空的基础类型。

答案 1 :(得分:5)

false可以安全地转换为boolbool?,因为它们之间存在隐式强制转换运算符。

另一方面,

null无法转换为bool,这就是null is bool返回false的原因。

is运算符不会(也不会)在乎您如何声明变量(如果有的话)。它仅指示运行时提供的值的类型。您也可以这样写:

WhatIsIt(false)

您希望该方法在这里表现如何?它只是尝试将值转换为两种类型(可以的),从而为两种类型都返回true。

为什么它对其他泛型不起作用,原因仅在于大多数泛型类型与其类型参数之间没有隐式转换。因此,以下操作无效:

string myString = new List<string>();

答案 2 :(得分:2)

Nullable<T>类实现了implicitexplicit运算符,它们在这种情况下即用即用,请看一下documentation

以下是source code的摘录:

[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;
}

答案 3 :(得分:0)

声明时

Nullable<bool> theNullableBoolThatsFalse = false;

theNullableBoolThatsFalse可以包含'true','false'或'null',类似theNullableBoolThatsNull可以包含布尔值和Null。当您分配Null时,它完全变为null不能是任何其他类型。它不引用任何对象。 Furthe Information About Nullable