2017-04-04 67 views
2

我不明白爲什麼這不起作用:理解C#的類型轉換

類:

public abstract class BaseObj 
{ 

    public bool IsValid => GetValidationErrors().Count == 0; 
} 

public class BaseObjWithId: BaseObj 
{ 
    public int Id { get; set; } 
} 

public class BaseReference<T> : BaseObj where T : BaseObjWithId 
{ 

    public T ObjReference { get; set; } 

} 

public class Foo: BaseObjWithId 
{ 
    public string Name{get;set;} 
} 

public class FooRef : BaseReference<Foo> 
{ 

} 

代碼聲明:

BaseReference<BaseObjWithId> foo= new FooRef(); 

錯誤CS0029無法隱式轉換類型...

這工作:

BaseReference<Foo> foo= new FooRef(); 

但我不明白爲什麼,因爲foo是一個BaseObjWithId ...

謝謝您的解釋

+4

當然,因爲Foo是帶附加功能的BaseObjectWithID,並且fooRef使用foo,所以BaseObjWithId是一個較小的版本,它不是相同的 – BugFinder

+1

因爲它沒有任何意義,你正在嘗試做什麼。你可以投它,但它沒有任何目的。 – Viezevingertjes

+0

因爲'FooRef'綁定到具體類'Foo'的實例,所以沒有辦法將它和它的基類綁定在一起,除非你讓FooRef過於通用,這更不是關於泛型的類型轉換 –

回答

1

你是誤會泛型是如何工作的關係類型遺產。您可以將FooRef類型的對象轉換爲類型BaseReference<Foo>的引用,因爲FooRef繼承自BaseReference<Foo>。但是,不能將BaseReference<Foo>轉換爲BaseReference<BaseObjWithID>,因爲與它們用作泛型類型參數的類型不同,這兩個泛型類沒有這種連接。

採取下面的例子:

public class Fruit {} 
public class Apple : Fruit {} 

任何Apple對象可以被存儲在一個Fruit參考因爲繼承確保它們之間的關係檢出:

Fruit f = new Apple(); 

然而,在非專利涉及每次使用不同的類型參數創建類的泛型版本時,這些版本都被視爲完全不同的類型。例如,雖然上面的隱式轉換會的工作,下面會失敗:

List<Fruit> f = new List<Apple>(); 

List<Fruit>List<Apple>是完全不同的類。它們之間沒有直接轉換,無論是隱式的還是顯式的。

1

你在找什麼,叫做covariance。在你的情況下 - 泛型中的協變。據this article它只是實現了有限的幾種類型:

這工作得很好:

IEnumerable<Derived> b = new List<Derived>(); 
IEnumerable<Base> a = b; 

這不起作用:

IList<Derived> b = new List<Derived>(); 
IList<Base> a = b; 

所以,你的情況,FooRef直接來自BaseReference<Foo>,所以它可以被鑄造成這種類型,而c#不能簡單地鑄造BaseReference<Foo>BaseReference<BaseObjWithId>,因爲泛型參數協方差的問題。

可能有一些變通方法,分離方法用硬編碼的轉換,從一個到另一種,但是,我想,這種行爲應該都可以避免。