我正在尝试使用 C# 为 Godot 中的游戏编写一个通用的保存/加载系统。
我想支持保存具有队列属性的对象。由于游戏代码有很多类,我希望避免为每个不同的类重复相同/相似的保存/加载代码。因此,我有一个主要的 util 类,在保存和加载时处理不同类型的属性。像 int、string、enum 等普通类型都工作正常。
基本上,我有一个
BankAccount
类,它有一个属性 Queue<Expense>
我正在执行以下步骤:
如果我将其投射到
Queue
,我会得到:
System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.Queue`1[scripts.finance.Expense]' to type 'System.Collections.Queue'.
如果我将其投射到
Queue<object>
,我会得到:
System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.Queue`1[scripts.finance.Expense]' to type 'System.Collections.Generic.Queue`1[System.Object]'.
这就是我的加载方法的相关部分:
if( propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Queue<>) ) {
Type genericArgument = propertyInfo.PropertyType.GetGenericArguments()[0];
Variant variant = Json.ParseString(stringVal);
Godot.Collections.Dictionary<string, Variant> queueDict = (Godot.Collections.Dictionary<string, Variant>)variant;
foreach (KeyValuePair<string, Variant> pair in queueDict) {
string queueElementString = (string)pair.Value;
object queueObject = CreateDefaultObject(queueElementString);
Queue<object> queue = (Queue<object>)propertyInfo.GetValue(newObject);
queue.Enqueue(queueObject);
}
return true;
}
此时,
newObject
是我新创建的BankAccount
对象,queueObject
是我新创建的Expense
对象。但我不知道如何在 Enqueue(queueObject)
对象的 Queue<Expense>
属性上调用 BankAccount
。
我还尝试获取该方法并调用它,使用:
MethodInfo methodInfo = typeof(Queue).GetMethod("Enqueue");
object invoke = methodInfo.Invoke(propertyInfo.GetValue(newObject), new object[] { queueObject });
但是,在这种情况下我遇到了以下异常:
ERROR: System.Reflection.TargetException: Object does not match target type.
(如果我尝试使用
typeof(Queue<object>).GetMethod("Enqueue");
则相同)
所以,我想了解,有没有一种方法可以在编译时不知道泛型类型的情况下将对象添加到泛型队列中?
如果这是不可能的,还有其他建议如何实现我的游戏加载,而不必为带有队列或列表的每个类实现单独的加载代码吗?
您是否尝试过构建完整的队列类型?
var queueType = typeof(Queue<>).MakeGenericType(genericArgument);
var myQueue = Activator.CreateInstance(queueType);
var insertMI = queueType.GetMethod("Enqueue");
insertMI.Invoke(myQueue, new[] { queueObject });
但是你将
Queue<object>
与 Queue<SomeType>
混合在一起,它们是完全不同的,你不能在它们之间进行转换。
相反,你应该使用
Queue<object> queue1 = new();
Queue<SomeType> queue2 = queue1.Cast<SomeType>();
但它会返回一个 IEnumerable