簡體   English   中英

使用null-coalescing運算符進行隱式轉換

[英]Implicit conversion with null-coalescing operator

我發現了我的程序的一個奇怪的行為,經過進一步的分析,我發現在我的C#知識或其他地方可能有問題。 我相信這是我的錯,但我無法在任何地方找到答案......

public class B
{
    public static implicit operator B(A values) 
    {
        return null; 
    }
}
public class A { }

public class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        B b = a ?? new B();
        //b = null ... is it wrong that I expect b to be B() ?
    }
}

此代碼中的變量“b”被計算為null。 我不明白為什么它是null。

我用谷歌搜索並在這個問題中找到了一個響應 - 使用官方規范隱式轉換Null-Coalescing運算符結果

但是按照這個規范,我找不到“b”為空的原因:(也許我讀錯了,在這種情況下我為垃圾郵件道歉。

如果A存在且不是可空類型或引用類型,則發生編譯時錯誤。

......事實並非如此。

如果b是動態表達式,則結果類型是動態的。 在運行時,首先評估a。 如果a不為null,則a將轉換為dynamic,這將成為結果。 否則,評估b,結果成為結果。

......事實並非如此。

否則,如果A存在且是可空類型,並且存在從b到A0的隱式轉換,則結果類型為A0。 在運行時,首先評估a。 如果a不為null,則打開a以鍵入A0,這將成為結果。 否則,b被評估並轉換為類型A0,這就成了結果。

...存在,從b到A0的隱式轉換不存在。

否則,如果A存在且從b到A存在隱式轉換,則結果類型為A.在運行時,首先計算a。 如果a不為null,則a成為結果。 否則,b被評估並轉換為類型A,這就是結果。

...存在,從b到A的隱式轉換不存在。

否則,如果b具有類型B並且從a到B存在隱式轉換,則結果類型為B.在運行時,首先計算a。 如果a不為null,則打開a以鍵入A0(如果A存在並且可以為空)並轉換為類型B,這將成為結果。 否則,b被評估並成為結果。

... b具有類型B,並且從a到B存在隱式轉換.a被評估為null。 因此,應評估b,結果應為b。

否則,a和b不兼容,並發生編譯時錯誤。 不會發生

我錯過了什么嗎?

為什么期望null-coalescing運算符返回new B() a不是null,所以a ?? new B() a ?? new B()評估為a

現在我們知道, a將被退回,我們需要確定結果的類型( T ),我們是否需要轉換aT

•否則, 如果b具有類型B並且從a到B存在隱式轉換,則結果類型為B.在運行時,首先計算a。 如果a不為null, 打開a以鍵入A0(如果A存在並且可以為空)並轉換為類型B,這將成為結果 否則,b被評估並成為結果。

AB存在隱式轉換,因此B是表達式的結果類型。 這意味着a將被隱式強制轉換為B 並且您的隱式運算符返回null

實際上,如果你寫var b = a ?? new B(); var b = a ?? new B(); (注意var ),你會看到編譯器推斷B是表達式返回的類型。

否則,如果b具有類型B並且從a到B存在隱式轉換,則結果類型為B.在運行時,首先計算a。 如果a不為null,則打開a以鍵入A0(如果A存在並且可以為空)並轉換為類型B,這將成為結果。 否則,b被評估並成為結果。

... b具有類型B,並且從a到B存在隱式轉換.a被評估為null。 因此,應評估b,結果應為b。

你在解釋這個錯誤。 沒有什么說在執行null檢查之前完成aB轉換。 它聲明在轉換之前完成了null檢查!

你的情況適合那個:

如果a不為null ,則打開a以鍵入A0(如果A存在且可為空)並轉換為類型B ,這將成為結果

嗯,規范說(我改為xy以減少混淆):

•否則,如果y具有類型Y並且存在從x到Y的隱式轉換,則結果類型為Y.在運行時,首先計算x。 如果x不為null,則x被解包為類型X0(如果X存在並且可以為空)並轉換為類型Y,這就成為結果。 否則,y被評估並成為結果。

有時候是這樣的。 首先,檢查左側x (僅為a )為null 但它本身並不是null的。 然后,左手側被使用。 然后運行隱式轉換。 它的類型B結果是...... null

請注意,這與以下內容不同:

    A a = new A();
    B b = (B)a ?? new B();

在這種情況下,左操作數是表達式( x ),其本身為null ,結果變為右側( y )。

也許引用類型之間的隱式轉換應該返回null (if和)僅當原始為null ,作為一種好的做法?


我想那些編寫規范的人可能會這樣做(但沒有):

•否則,如果y具有類型Y並且存在從x到Y的隱式轉換,則結果類型為Y.在運行時,首先計算x並將其轉換為類型Y.如果該轉換的輸出不為null,輸出成為結果。 否則,y被評估並成為結果。

也許那會更直觀? 無論轉換的輸入是否為null它都會強制運行時調用隱式轉換。 如果典型的實現快速確定null → null ,那應該不會太昂貴。

我們需要看的部分是null-coalescing表達式的編譯時類型。

否則,如果b具有類型B並且從a到B存在隱式轉換,則結果類型為B.在運行時,首先計算a。 如果a不為null,則打開a以鍵入A0(如果A存在並且可以為空)並轉換為類型B,這將成為結果。 否則,b被評估並成為結果。

把它變成偽代碼:

public Tuple<Type, object> NullCoalesce<TA, TB>(TA a, TB b)
{
    ...
    else if (a is TB) // pseudocode alert, this won't work in actual C#
    {
        Type type = typeof(TB);
        object result;
        if (a != null)
        {
            result = (TB)a; // in your example, this resolves to null
        }
        else
        {
            result = b;
        }
        return new Tuple<Type, object>(type, result);
    }
    ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM