簡體   English   中英

C#; InvalidCastException,怎么了?

[英]C#; InvalidCastException, what´s wrong?

我想將列表的對象轉換為它的子類。 為此,我使用Casting 填充 List<BaseClass> 到 List<ChildClass>

現在,當我執行代碼時,我總是在 System.Core.dll 中得到一個 InvalidCastException ""The Object Item cannot be cast to SubItem "

[Serializable]
public class SubItem: Item
{
    public SubItem(int id) : base( id)
    {          
    }
}


public getStuff(int id){
 //where the Error is thrown
//Inventory has Items in it, furthermore atm Inventory is definitely not     empty, but could be later on
 var items = Inventory.FindAll(x=> x.id==id).Cast<SubItem>().ToList();
}

項目來自 API,我無法在那里更改任何內容。 項目繼承自 IEquatable。

LINQ 肯定可以正常工作,但是當我投射時出現錯誤。 我做錯了什么?

我將假設您的財產Inventory是泛型類型Item (例如: ICollection<Item> )的強類型集合/列表/IEnumerable。

如果一項或多項不屬於泛型參數中指定的類型,則在調用Cast時將發生InvalidCastException 請參閱 Microsoft 頁面Enumerable.Cast中的詳細信息。 為了解決這個問題,您只需要檢索該類型的項目,這些項目將在過濾器期間對它們執行強制轉換。 這可以通過Enumerable.OfType來完成。 然后您的代碼變為:

var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();

從文檔Enumerable.Cast

如果一個元素無法轉換為 TResult 類型,則此方法將引發異常。 要僅獲取那些可以強制轉換為 TResult 類型的元素,請使用 OfType 方法而不是 Cast(IEnumerable)。


根據這些評論進行編輯

確定返回的所有項目都是Item而不是SubItem類型。 這解釋了異常。

...說列表由項目組成,這就是為什么我想將它們向下轉換為子項目。

您在問題中發布的繼承層次結構是System.Object -> Item -> SubItem 我包括 Object ,因為我假設我們正在處理引用類型,並且所有東西最終都繼承自 System.Object )。 這意味着SubItem可以轉換為ItemSystem.ObjectItem實例可以轉換為System.Object 然而,逆是不正確的,你不能投出圖表。 System.Object的實例不能成為Item並且Item不能成為SubItem

擁有一個通用的List<Item>很好,它可以包含類型SubItemItem或任何派生自Item東西。 但同樣,您不能將Item的實例轉換為SubItem

如果這還不清楚,那么我建議您閱讀有關繼承和多態的一些內容,這是一個不同的主題,但如果您想知道為什么使用繼承以及是什么使它成為如此出色的抽象工具,這也非常重要。

可能是您列表中的某些項目不是派生類類型,您應該能夠在調試器中看到這一點。 另外,正如有人指出的那樣,您可能必須在進行轉換之前從數據庫中取回數據,因此 linq 提供程序可能無法為您執行此操作。

因此,您可以嘗試以下任一方法:

  • 過濾掉不屬於 SubItem 的項目
var items = Inventory.FindAll(x=> x.id==id).OfType<SubItem>().ToList();
  • 轉換前從數據庫中取回數據
var items = Inventory.FindAll(x=> x.id==id).ToList().Cast<SubItem>().ToList();
  • 或者,如果 linq 提供程序不能執行 OfType,則將兩者結合使用
var items = Inventory.FindAll(x=> x.id==id).ToList().OfType<SubItem>().ToList();

假設 Inventory 包含一個“Item”列表,並且您想獲得一個“SubItem”列表,將您的行替換為:

var items = Inventory.Where(x => x.id == id).Select(x => new SubItem(x.id)).ToList();

因此,第一部分將為您提供符合您條件的項目,第二部分將為每個項目創建一個新的子項目並為您提供它們的列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM