Reputation: 137398
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 Bag
s, and they all hold their own special type of Marble
. Each type of Marble
has its own set of Nicknames (string
s).
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:
RedMarble.Nicknames
hides Marble.Nicknames
. Does it seem valid to go ahead and mark it new
?Upvotes: 3
Views: 5082
Reputation: 15618
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:
abstract class Bag<T> where T:marble {
public void DumpBag()
{
// here you can use
// (IEnumerable<string>)typeof(T).GetProperty("Nicknames").GetValue(null, null);
}
}
class RedBag : Bag<RedMarble> {
}
class BlueBag : Bag<BlueMarble> {
}
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 in RedMarble
and BlueMarble
, and then just accessed in DumpBag
directly as Nicknames
rather than using reflection.
Upvotes: 3