[英]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
),我們是否需要轉換a
以T
。
•否則, 如果b具有類型B並且從a到B存在隱式轉換,則結果類型為B.在運行時,首先計算a。 如果a不為null, 則打開a以鍵入A0(如果A存在並且可以為空)並轉換為類型B,這將成為結果 。 否則,b被評估並成為結果。
從A
到B
存在隱式轉換,因此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
檢查之前完成a
到B
轉換。 它聲明在轉換之前完成了null
檢查!
你的情況適合那個:
如果a不為null ,則打開a以鍵入A0(如果A存在且可為空)並轉換為類型B ,這將成為結果 。
嗯,規范說(我改為x
和y
以減少混淆):
•否則,如果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.