C# 中派生類對象列表賦值給基類列表:協變問題
在 C# 編程語言中,將派生類對象列表賦值給基類引用列表會引發協變問題。當派生類具有基類中不存在的附加屬性或方法時,就會出現此問題。
例如,考慮以下代碼:
class Animal { } class Giraffe : Animal { } static void Main(string[] args) { List<Giraffe> giraffes = new List<Giraffe>(); List<Animal> animals = giraffes; // 编译时错误 }
在此代碼中,Giraffe 對象的列表被賦值給 Animal 引用的列表。但是,由於協變問題,此賦值在編譯時失敗。
協變和不變性
C# 中的泛型可以是協變或不變的。協變允許基類引用也引用派生類對象,而不變性則阻止此類賦值。對於列表,默認行為是不變性,這意味著 List
解決方法
為了解決這個問題,有幾種解決方法:
List<Animal> animals = (List<Animal>)giraffes; // 不推荐,可能导致运行时错误
但是,不建議使用此顯式轉換,因為它如果轉換無效,可能會導致運行時錯誤。
List<Animal> animals = giraffes.ConvertAll(g => (Animal)g);
可以通過自定義接口實現顯式指定泛型類型的協變。通過實現 ICovariant<out T> 接口,類可以允許其對象使用基類的泛型類型進行引用賦值。 (注意:ICovariant<out T>
在C#中並不存在,實際解決方法是使用IEnumerable<out T>
,因為ListIEnumerable<Animal>
作為目標類型,因為IEnumerable<out T>
支持協變。
IEnumerable<Animal> animals = giraffes; // 这行代码是有效的
選擇哪種方法取決於具體情況和對代碼健壯性的要求。 ConvertAll
方法通常是首選,因為它更安全,並且明確地表達了轉換意圖。 使用IEnumerable<Animal>
則更符合泛型編程的原則,避免了顯式轉換的風險。
以上是我可以將派生類對象的列表分配給C#中的基類列表嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!