![](/img/trans.png)
[英]how to access properties in derived class stored in a list of the base class
[英]How to access derived objects properties when they are stored in a Parent typed collection?
我從事RPG方面的工作,並且對如何制作世界上所有物品的全球清單感到困惑。 我使用Unity3D。
我的物品可能是武器,貨幣,Macscots和許多衍生類。
所以我有一個基本的Class Item(簡化代碼)
public class Item{
public int Id {get;set;}
public Vector2 GeoCoord{get;set;}
public int OwnerId{get;set;}
public string State{get;set;}
public string Name{get;set;}
public Type Type{get;set;}
}
和子類
public class WeaponModel: Item {
public Type CloseTargetBehavior{get;set;}
public Type DistantTargetBehavior{get;set;}
...
}
public class MascotModel: Item {
public MascotCategory Category {get; set;}
...
}
public class ConsumableModel: Item {
public float Price {get; set;}
...
}
出於節省目的和其他原因,我想將這些派生類的所有實例存儲在字典(或其他任何東西)中。 但我讀到它不建議將多類型對象存儲在集合中,因為您只能訪問它們的公共屬性(此處為Item的類屬性)。
那么,擁有所有對象的全局列表並仍然可以訪問其屬性的最佳方法是什么?
編輯1:添加了一些用法詳細信息
該集合的第一個用途是將其用作一些“工廠”的描述:
1)當游戲開始時,我反序列化一個JSON文件來構建這個唯一的集合。 我使用http://www.dustinhorne.com/post/Json-NET-for-Unity-Developers。我使用settings.TypeNameHandling = TypeNameHandling.All; 保留所有類/子類描述的參數。
2)不同的具體GameObject(可以同化為View元素)被用於2Dmap,3Dworld,清單...中,但是每個表示形式都引用子類實例(WeaponModel或MascotModel或...)。 例如:對地圖上某個項目或3D視圖中的項目的更改都會改變模型的狀態。
我想到了“ if(typeOf(WeaponModel))else if ...”,但這是我困惑的起點。 我正在尋找一種更通用的方式來執行此操作,因為我不知道我將擁有多少個子類。
我嘗試了一些動態轉換,但我讀到它在C#中是不可能的。 這是我的嘗試:
Type type = Items[key].GetType();
Debug.Log(type()); //WeaponModel but I have no access to the method/property
Item item = (type) Items[key]; // Cast don't work
Debug.Log(item.CloseTargetBehavior) // Still no access to subclass property
Item item = (WeaponModel) Items[key]; // Cast works because it is a declarative type
Debug.Log(item.CloseTargetBehavior) // I have ccess to subclass property
問題是要提供所有項目的單個全局列表,因此這將完全解決該情況。
要存儲項目:
public static List<Item> GlobalItems = new List<Item>();
為了訪問派生類型的屬性,必須將Item強制轉換為其派生類型。
要確定其當前類型,請使用:
var itemType = item.GetType();
要將項目用作派生類型,請執行以下操作:
Item item = GlobalItems[0];
DerivedItem derivedItem = item as DerivedItem;
if(derivedItem == null)
{
Console.WriteLine("Item is not a DerivedItem");
}
要從列表中獲取特定類型的所有項目:
var derivedItems = GlobalItems.Where(item => item.GetType() == typeof(DerivedItem)).Select(item => (DerivedItem)item);
我相信這里真正的問題是用於離線存儲數據的串行器/解串器。 無論做出什么選擇,解串器都必須了解類型,以便在導入保存數據時重新創建正確類型的對象。 .Net XML和Binary序列化程序都存儲詳細的類型信息,並反序列化為正確的類型。
如果用於保存所有數據的主容器(序列化/反序列化的根對象)具有要存儲的每種派生類型的List <>,則可以對存儲的數據進行類型化訪問,而無需花很多時間。 我根本看不到使用字典的意義,因為您將項目ID和所有者ID存儲在Item基類中,並且可以在反序列化后掃描列表以將項目重新附加到其關聯所有者。
The only thing you MIGHT want a dictionary for is to create an ItemContainer object with a common/generic method for adding items like: Container.AddItem<WeaponModel>(WeaponModel item); or accessing the lists based on the derived type Container.GetList<WeaponModel>() Container.GetItemByID<WeaponModel>(int id) so that you don't have to explicitly create a container class with all the typed lists.. simply adding a derived object using these methods would create a list of the derived type and add/remove/access data from it in a transparent manner, and it would still work correctly with the serializer/deserializer.
編輯:根據要求,提供一種通用技術的快速示例,用於存儲以強類型方式訪問的,從Item派生的任何類型的數據:
using System; using System.Collections.Generic; public class Item { public int Id { get; set; } public Vector2 GeoCoord { get; set; } public int OwnerId { get; set; } public string State { get; set; } public string Name { get; set; } public Type Type { get; set; } } public class ItemContainer { private Dictionary<Type, object> items; public ItemContainer() { items = new Dictionary<Type, object>(); } public T Get<T>(int id) where T: Item { var t = typeof(T); if (!items.ContainsKey(t)) return null; var dict = items[t] as Dictionary<int, T>; if (!dict.ContainsKey(id)) return null; return (T)dict[id]; } public void Set<T>(T item) where T: Item { var t = typeof(T); if (!items.ContainsKey(t)) { items[t] = new Dictionary<int, T>(); } var dict = items[t] as Dictionary<int, T>; dict[item.Id] = item; } public Dictionary<int, T> GetAll<T>() where T : Item { var t = typeof(T); if (!items.ContainsKey(t)) return null; return items[t] as Dictionary<int, T>; } }
只是為Ascendion的答案(他因撰寫而獲得全部功勞)添加了一種可能性,還可以添加以下方法:
public Dictionary<int, T> GetAll<T>() where T: Item
{
var t = typeof(T);
if (!items.ContainsKey(t)) return null;
var derivedItemDict = new Dictionary<int,T>();
foreach(var item in items[t]) {
derivedItemDict.Add(item.Key, (T)item.Value);
}
return derivedItemDict;
}
然后,您可以例如執行以下操作:
Items.GetAll<Weapon>();
為您返回Dictionary<int, Weapon>
。即,它將返回您我認為您要搜索的強類型詞典。 但是請注意,如果您經常使用此功能,則應將其結果確實保存在更改之間,這樣就不必重復執行所有這些強制轉換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.