你忘記隱式運算符是在編譯時確定的。這意味着你所擁有的null
實際上是LookupCode<T>
類型(由於類型推斷在三元運算符中工作的方式),並且需要使用隱式運算符將其轉換爲字符串;這就是你的例外。
void Main()
{
byte? reviewMonth = null;
string result = reviewMonth == null
? null // Exception here, though it's not easy to tell
: new LookupCode<object> { Description = "Hi!" };
result.Dump();
}
class LookupCode<T>
{
public string Description { get; set; }
public static implicit operator string(LookupCode<T> code)
{
if (code != null) return code.Description;
throw new InvalidOperationException();
}
}
無效操作不會對第三個操作數發生,它發生在第二個 - null
(實際上是一個default(LookupCode<object>)
)是string
型的沒有,所以隱式操作符被調用。隱式運算符引發無效操作異常。
你可以很容易地看到這一點,如果您使用的是稍微修改的代碼是正確的:
string result = reviewMonth == null
? default(LookupCode<object>)
: "Does this get evaluated?".Dump();
你仍然可以得到一個無效的操作異常,第三個操作數未評估。這在生成的IL中當然是非常明顯的:兩個操作數是兩個獨立的分支;他們都無法執行。和第一支有另一個非常明顯的事情:
ldnull
call LookupCode`1.op_Implicit
它甚至不是隱藏在任何地方:)
解決方法很簡單:使用顯式類型null
,default(string)
。 R#完全是錯誤的 - (string)null
和null
不一樣,在這種情況下R#有錯誤的類型推斷。
當然,這是在C#規範(14.13 - 有條件的操作者)的所有描述:
所述的第二和第三個操作數:操作員控制的條件表達式的類型?。
設X和Y爲 爲第二個和第三個操作數的類型。然後,
- 如果X和Y是相同的類型,那麼這是條件表達式的類型。否則,如果存在從X到Y而不是從Y到X的隱式轉換(第13.1節),則Y是條件表達式的類型 。否則,如果存在從Y到X而不是從X到Y的隱式轉換(第13.1節),則X是條件表達式的類型 。
- 否則,不能確定表達式類型,併發生編譯時錯誤。
在你的情況下,隱式轉換存在從LookupCode<T>
到string
,而不是相反的,所以類型LookupCode<T>
優選string
。有趣的一點是,因爲這是所有在編譯時完成的,轉讓的LHS實際有差別:
string result = ... // Fails
var result = ... // Works fine, var is of type LookupCode<object>
ReSharper的是錯在這裏 –
什麼是'MonthNames.AllValues'的類型?一個MCVE會有幫助 –
可能的重複[有條件的操作符賦值可爲Nullable類型?](http://stackoverflow.com/questions/75746/conditional-operator-assignment-with-nullablevalue-types) –
raidensan