2

I have a save game editor. It uses a library that can read the file and return it in a form of an object. Within that object is an ItemSave object.

Also, to be able to interpret the data in the ItemSave object, I need more info (from an xml) which I get by a method in my own code that returns the ItemData object. They have all different fields, except of the "id" field. The id field is used to make the connection between the two.

For each ItemData variant (there is about 1500 of those, might expand, out of my control) I can have numerous ItemSave object (eg. a gun will always be called a gun and will always have clip size of 10, but number of bullets loaded may vary, etc).

As you can see, one class is pretty useless without the other, so I'd like to combine them.

Currently, I have an ItemBinder class that holds the reference to both ItemData and ItemSave and also has fields of both of them to flatten it out (So I can access data with ItemBinder.Value, not ItemBinder.ItemSave.Value). However, this is bad code and is hard to maintain.

I could drop all the fields in the ItemBinder and just have the two references and suffer through having longer paths, but I'd like the ItemBinder to seem as "the" class that has all the data, the other two being hidden away.

Additional complication is that I'd have to define several methods in the ItemBinder class that would manipulate data from both of the two classes. That may or may not be a problem depending on solution to this, if there is one.

Also, all data will be a reference type, so that simplifies things a bit.

  • What is the question? You have already explored the alternatives. C# doesn't support delegation directly, which is the solution you seem to be searching for. For this reason, separate classes will be the easiest to maintain. – Frank Hileman Sep 30 '16 at 0:33
  • My question is "Have I missed something?". I'm not that well versed with C# and people do come up with most ingenious solutions. – Karlovsky120 Sep 30 '16 at 0:38
  • The only place I have seen something like delegation work in C# is using the property grid in visual studio, which has something like "virtual properties". I don't think this would help you. C# is a simple language in many ways. Separate classes, without the convenience properties, will be the easiest to maintain. – Frank Hileman Sep 30 '16 at 0:42
1

As @FrankHileman has mentioned, what you are looking for is delegation or possibly multiple inheritance. Neither are features that C# provides. However, you could achieve this by compile time code generation (you could also do runtime generation or possibly muck around with dynamics, but the earlier the better in general for this sort of thing). The most widespread way of accomplishing this would be T4 Templates. I do not have a C# IDE on hand so I cannot flesh out this answer fully, but I have done similar things in the past. The general procedure would be:

  1. Set up a T4 template to build into your project (this is easily done with any modern VS).
  2. Write a T4 template to generate a partial ItemBinder (for example).
  3. In your own file, define the other half of ItemBinder with the non delegated members.

You would accomplish 2 through reflection. For each of ItemData and ItemSave you would get all of the public properties (e.g. typeof(ItemData).GetProperties()) loop over them and emit a string delegating that property, e.g. through a method like

string DelegateProperty(PropertyInfo property, string backingMember) 
{
    string declaration = String.Format("public {0} {1} {{ ", property.PropertyType.FullName, property.Name);
    if (property.GetGetMethod() != null)
    {
        declaration += String.Format("get {{ return {0}.{1}; }} ", backingMember, property.Name;
    }
    if (property.GetSetMethod() != null)
    {
        declaration += String.Format("set {{ {0}.{1} = value; }} ", backingMember, property.Name;
    }
    declaration += "}";
    return declaration;
}

You would also write a similar method for the, well, methods (this is more involved). You may have to go even more in depth if you also want to capture the attributes on those properties or also implement interfaces the type might.

I'm somewhat in two minds about how wise this is. On the one hand having computers generate utterly mindless code has a lot of upsides (less cruft to read, no chance of stupid mistakes), but on the other hand you are complicating your build process, tying yourself to particular tools and potentially making things a little more tricky for future maintainers.

0

I understand why ItemBinder may make sense, given than there are many ItemSave per ItemData. And in fact it seems that ItemData won't change during the lifetime of the application. In this case you would ideally add a ItemData property in ItemSave, but you can't modify ItemSave (and making a derived class is pointless because the third party code won't use it). So you create ItemBinder.

Yet ItemBinder is not a good solution, as it add a new maintenance problem with the convenience properties.

I would suggest to create an extension method for ItemSave that allows you to get the appropiate ItemData and then continue to use ItemSave directly. To get info from ItemData call the extension method. Edit: your additional methods may be extension methods too.

Of course you would use a dictionary to store your ItemData for fast retrieval.

  • I don't think an extension method would be any easier to maintain than a normal instance method, for the delegation needed. – Frank Hileman Oct 1 '16 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.