Any way to get the definition of a property from the code itself?

61 views Asked by At
public abstract class Unit
{
    public abstract List<Move> allowedMoves{get;}
}

public class Javelineer : Unit
{
    public List<Move> allowedMoves =>
        new List<Move> {Move.Impale, Move.JavelinThrow, Move.ShieldBlock};
}

public class Dragon : Unit
{
    public List<Move> allowedMoves =>
        new List<Move> {Move.BreatheFire, Move.Swipe, Move.Bite, Move.Devour, Move.TailBash};
}

The X:

Given the above code, if and how can I retrieve the allowed moves of a given unit without necessarily instantiating a new object?

I know I can retrieve the property with this code:

typeof(Javelineer).GetProperty("allowedMoves")

But if and how can I retrieve the definition of this property?

The Y:

The client (web browser) must send the game server the player's unit. This includes the unit's type and moves this unit is able to perform (4 out of all available; similarily to Pokemon).

While the validation (of course) is performed on the server, the browser still needs to get a list of available unit types and allowed moves.

In order not to duplicate code, I would like to avoid hard-coding this data in Javascript.

Having read some excellent SO questions & answers I think I can retrieve all available units with code similar to this:

Assembly.GetExecutingAssembly().GetTypes().Where(
    type => type.BaseType == typeof(Unit)
).Select(type => type.Name).ToList()

I'd call this code on server startup, cache the result and send the cached result to every connecting client, because I have feeling this code is likely expensive to call.

But how can I retrieve the list of allowed moves?

1

There are 1 answers

0
Lasse V. Karlsen On BEST ANSWER

You have a couple of options, but TL;DR: Construct the object instance and read the property.

In any case, here are some options, creative minds might be able to find a couple more even.

  1. Construct the instance, read the property.

    This is your best option code-wise because it will be easy to understand, maintain, bugfix.

  2. Rewrite the code to allow for easy detection of the values using reflection

    One way to do this would be to use attributes, tagging the property or object with the legal moves. However, to avoid having the bug that the attributes does one thing, the code another, you might have to change the code to use the attributes as well, which would be a performance hit.

    Additionally, reading those attributes would likely construct many more objects than your original object.

  3. Use mono.cecil or some other IL-inspection library to decode the code of the property getter and finding the construction of that list, extracting the values being added to the list. You would essentially either have to dumb down the code of that property to be on par with what you have right now (and never allow it to become more complex) or basically simulate execution of code.

    This is like constructing a flotilla of space warships with enough firepower to demolish a local starsystem, just to kill an ant.

Bottom line, construct the object instance, read the property.