簡體   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