我正在制作游戏(请参阅http://haighshroom.blogspot.com了解上下文)并使用XML文件保存/加载游戏。它目前使用不同的结构作为每个类的保存格式,但继续更新保存文件结构是令人厌倦的,所以我想尝试采用以下通用方法。
假设我有3个类,它们都继承自BaseClass:
Class1,它具有Property1,Property2(假设所有属性都是整数)
Class2,具有Property2,Property3
Class3,具有Property1,Property3
现在我的新广义SaveStruct看起来像这样:
public struct EntityStruct
{
public string ClassName;
public int Property1;
public int Property2;
public int Property3;
public EntityStruct()
{
ClassName = "";
Property1 = Property2 = Property3 = 0;
}
}
在保存/加载特定实体时,我想实现以下Pseudocode(两个函数都是从BaseClass调用的):
public EntityStruct GetSaveStruct()
{
EntityStruct es = new EntityStruct();
es.ClassName = this.GetType().Name;
if Exists(this.Property1) es.Property1 = Get(this.Property1);
if Exists(this.Property2) es.Property2 = Get(this.Property2);
if Exists(this.Property3) es.Property3 = Get(this.Property3);
}
public void LoadFromStruct(EntityStruct es)
{
BaseClass e = (BaseClass)(Activator.CreateInstance(null, GV.NameSpace + es.ClassName).Unwrap());
if Exists(e.Property1) Set(e.Property1 = es.Property1);
if Exists(e.Property2) Set(e.Property2 = es.Property2);
if Exists(e.Property3) Set(e.Property3 = es.Property3);
}
我不知道如何定义的部分是:
-Exists(e.Property1) - 这需要使用Reflection来确定实例e是否定义了Property1(我们从BaseClass调用它,所以我们不知道不使用Reflection)。
-Get(e.Property1) - 如果实例e存在属性1,我们需要获取其值
-Set(e.Property1 = es.Property1) - 如果属性1确实存在于实例e中,我们需要设置其值
非常感谢。
答案 0 :(得分:3)
您可以尝试使用此代码
public void ShallowCopyValues<T1, T2>(T1 firstObject, T2 secondObject)
{
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
var firstFieldDefinitions = firstObject.GetType().GetFields(bindingFlags);
IEnumerable<FieldInfo> secondFieldDefinitions = secondObject.GetType().GetFields(bindingFlags);
foreach (var fieldDefinition in firstFieldDefinitions)
{
var matchingFieldDefinition = secondFieldDefinitions.FirstOrDefault(fd => fd.Name == fieldDefinition.Name &&
fd.FieldType == fieldDefinition.FieldType);
if (matchingFieldDefinition == null)
continue;
var value = fieldDefinition.GetValue(firstObject);
matchingFieldDefinition.SetValue(secondObject, value);
}
}
答案 1 :(得分:2)
所有这一切的起点是System.Type
类。您可以使用e.GetType()
为您的类型获取此类的实例。
要查找字段,请使用GetField
。如果返回null
,则该字段根本不存在。
如果它返回一个值(类型为FieldInfo
),则使用GetValue
获取值,并使用SetValue
进行设置。
反射速度相对较慢,因此如果需要考虑性能,请提前使用System.Type.getType(name)
抓取System.Type
对象并获取FieldInfo
个对象。您不需要该类的实际实例来执行这两个操作中的任何一个,但显然您需要它来获取和设置字段值。