2010-01-20 62 views
1
public class Foo : IFooBarable {...} 
public class Bar : IFooBarable {...} 

那麼爲什麼會這樣不會編譯...內聯如果和接口(多態性)

int a = 1; 
IFooBarable ting = a == 1 ? new Foo() : new Bar(); 

但這會...

IFooBarable ting = a == 1 ? new Foo() : new Foo(); 
IFooBarable ting = a == 1 ? new Bar() : new Bar(); 
+1

此功能的最壞副作用是'int? x =條件? 42:null;'編譯失敗:( – 2010-01-20 17:05:20

回答

7

編譯器第一個嘗試計算右邊表達式:

? new Foo() : new Bar(); 

沒有隱式轉換這兩者之間的差異因此是錯誤信息。您可以這樣做:

IFooBarable ting = a == 1 ? (IFooBarable)(new Foo()) : (IFooBarable)(new Bar()); 
+0

IFooBarable ting = a == 1?(IFooBarable)new Foo():new Bar();) – gingerbreadboy 2010-01-20 19:10:47

5

這在C#語言規範的第7.13節中有介紹。本質上,殺死這種情況的是,三值操作數的兩個值的類型之間必須存在隱式轉換。這種轉換被認爲是變量類型的缺失。

因此,Foo必須可轉換爲Bar,反之亦然。編譯錯誤也不會發生。

後者2工作,但因爲他們只考慮1類型(FooBar)。因爲他們是相同的類型確定表達式的類型是簡單的,它工作正常。

1

因爲條件表達式的類型總是從其兩部分推斷出來,而不是從要應用結果的變量推斷出來。這種推斷只適用於類型相同或一個參考與另一個相兼容的情況。在這種情況下,兩種類型中的任何一種都不能與另一種兼容。

4

只需在此處添加一點正確的答案:有兩條設計指導原則可以達到此規範。

首先是我們從「內部到外部」的理由。當你說

double x = 2 + y; 

首先我們x的類型,那麼,2型,則Y的類型,則(2 + y)的類型,最後,我們制定出是否x和(2 + y)具有兼容的類型。但是我們不使用x的類型來決定2,y或2 + y的類型。

的原因,這是一個很好的規則是,因爲往往是「接收器」的類型正是我們正在設法解決:

void M(Foo f) {} 
void M(Bar b) {} 
... 
M(x ? y : z); 

是什麼,我們在這裏做什麼?我們必須計算出條件表達式的類型,以便進行重載解析,以確定這是否將轉至Foo或Bar。因此,我們不能使用事實上,這就是說,在我們分析條件表達式的類型時去了Foo!這是一個雞與雞蛋的問題。

此規則的例外是lambda表達式,其中從他們的上下文中獲取它們的類型。使這一功能正常工作是非常複雜的;如果您有興趣,請參閱lambda表達式與匿名方法的blog series

第二個元素是我們從來沒有「爲你提供一種類型的魔術」。當我們從一系列事物中推斷出一種類型時,我們總是推斷出一種在我們面前實際上是正確的類型。

在您的例子,分析是這樣的:

  • 工作出結果
  • 工作出了替代
  • 類型的類型找到與兼容最好的類型都在結果和替代
  • 請確保存在從條件表達式類型到使用條件表達式的事物類型的轉換。

符合第一點,我們沒有理由從外到內;我們不會使用這樣一個事實,即我們知道要找出表達式類型的變量的類型。但有趣的是現在,當你有

b ? new Cat() : new Dog() 

我們說「條件表達式的類型是集合最好的類型{貓,狗}」。我們不會說「條件表達式的類型是與貓和狗兼容的最佳類型」。這將是哺乳動物,但我們不這樣做。相反,我們說「結果必須是我們真正看到的東西」,在這兩種選擇中,既不是明顯的贏家。如果你說

b ? (Animal) (new Cat()) : new Dog() 

那麼我們有一個動物和狗之間的選擇,動物是明確的贏家。

現在請注意,我們實際上在進行此類型分析時並未正確實施C#規範!有關該錯誤的詳細信息,請參閱我的article

+1

很好的回答,非常詳細! – gingerbreadboy 2010-01-20 19:29:50

+2

「......與貓和狗兼容的最佳類型,這將是哺乳動物......」實際上,「貓」和「狗」這兩個類都來源於「食肉動物」,但無論如何。 ;-) – 2010-01-21 22:55:09