Haighstrom
Haighstrom

Reputation: 607

Using Reflection to copy across equivalent properties between struct and class

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

Answers (2)

Ganesh Sittampalam
Ganesh Sittampalam

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

Yanshof
Yanshof

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

Related Questions