Reputation: 607
I'm making a game (see http://haighshroom.blogspot.com for context) and saving/loading the game using an XML file. It currently uses a different struct for the save format of each class, but continuing to update the save file structure is proving tiresome so I want to try and adopt the following generalised method.
Let's assume I have 3 classes, which all inherit from BaseClass:
Class1, which has Property1, Property2 (let's say all properties are ints)
Class2, which has Property2, Property3
Class3, which has Property1, Property3
Now my new generalised SaveStruct would look like this:
public struct EntityStruct
{
public string ClassName;
public int Property1;
public int Property2;
public int Property3;
public EntityStruct()
{
ClassName = "";
Property1 = Property2 = Property3 = 0;
}
}
When saving/loading a particular entity, I want to achieve the following Pseudocode (both functions called from 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);
}
The parts I don't know how to define are:
-Exists(e.Property1) - this needs to use Reflection to determine whether the instance e has Property1 defined (we are calling this from BaseClass so we don't know without using Reflection).
-Get(e.Property1) - if Property 1 does exist for an instance e, we need to get its value
-Set(e.Property1 = es.Property1) - if Property 1 does exist from an instance e, we need to set its value
Many thanks.
Upvotes: 3
Views: 686
Reputation: 29100
The starting point for all this is the System.Type
class. You can get an instance of this for your type using e.GetType()
.
To look for a field, use GetField
. If that returns null
, then the field doesn't exist at all.
If it returns a value (of type FieldInfo
) then use GetValue
to get the value and SetValue
to set it.
Reflection is relatively slow, so if performance is a concern, grab the System.Type
object ahead of time with something like System.Type.getType(name)
and also get the FieldInfo
objects. You don't need the actual instance of the class to do either of those two operations, though obviously you need it to get and set the field values.
Upvotes: 3
Reputation: 9926
you can try use this code
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);
}
}
Upvotes: 4