I’m going to do my best to explain my vision here. This is a very lame made-up example. I’ve got a few different types of Bags, and they all hold their own special type of Marble. Each type of Marble has its own set of Nicknames (strings).
Unfortunately, there are other things besides the Marble in the Bag, so generics won’t help me here.
// Bags
abstract class Bag {
protected Type MarbleType { get; }
protected List<Marble> _marbles;
public void DumpBag()
{ ... }
}
class RedBag : Bag {
override Type MarbleType { get { return typeof(RedMarble); } }
}
class BlueBag : Bag {
override Type MarbleType { get { return typeof(BlueMarble); } }
}
// Marbles
abstract class Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>() {
"Marble", "RollyThing"
}
}
}
}
class RedMarble : Marble {
public static IEnumerable<string> Nicknames {
get {
return new List<string>(Marble.Nicknames) {
"Ruby"
};
}
}
}
class BlueMarble : Marble { ... }
So now we get to the details, the implementation of DumpBag(). Consider the following call:
Bag b = new RedBag();
b.GetMarbles();
b.DumpBag();
I would like it to print:
Bag of Marbles (aka "Marble", "RollyThing", Ruby"):
- Marble 1
- Marble 2
...
We see that, in order to print that heading, the Bag must be able to have knowledge of the derived type of Marble, independent of any actual instances. It gets a concatenation of the Nicknames of the Marble base class, but also the derived RedMarble.
DumpBag needs to do a kind of ‘static virtual call’. I’ve started implementing DumpBag with the following:
public void DumpBag() {
PropertyInfo pi = this.MarbleType.GetProperty("Nicknames", BindingFlags.Static);
IEnumerable<string> nicknames = pi.GetValue(null, null); // No instance
StringBuilder sb = new StringBuilder("Bag of Marbles (aka ");
foreach (string nn in nicknames)
sb.Append("\"" + nn + "\", ");
Console.WriteLine(sb.ToString());
...
}
My questions:
- Is this sane? Hopefully I have (or I can) explain my rationale for why I’ve gone this route.
- I get a warning (of course) that
RedMarble.NicknameshidesMarble.Nicknames. Does it seem valid to go ahead and mark itnew?
You’ll find all you’re missing is an explicit cast:
(List<string>)this.MarbleType.GetProperty("Nicknames").GetValue(null, null);This worked fine for me when I tested it.
And as discussed in the comments, no you shouldn’t be using the new keyword really, you’re better off naming the base class static method to something else so there is no ambiguity. You are after all in control of this and not using someone else’s code.
Now, should you do it this way?
Well, first surely you want to use generics not defined methods to return types:
Of course the second thing you could do is make this not static, in which case the property will be abstract in
Marble, and overridden inRedMarbleandBlueMarble, and then just accessed inDumpBagdirectly asNicknamesrather than using reflection.