我会尽力在这里解释我的愿景。这是一个非常蹩脚的例子。我有几种不同类型的Bag
,它们都拥有自己特殊类型的Marble
。每种类型的Marble
都有自己的一组昵称(string
s)。
不幸的是,Bag中除了Marble之外还有其他的东西,所以泛型不会帮助我。
// 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 { ... }
现在我们开始详细介绍DumpBag()
的实现。请考虑以下呼叫:
Bag b = new RedBag();
b.GetMarbles();
b.DumpBag();
我想要打印:
Bag of Marbles (aka "Marble", "RollyThing", Ruby"):
- Marble 1
- Marble 2
...
我们看到,为了打印该标题,Bag
必须能够了解Marble
的派生类型,而不管任何实际情况。它得到Nicknames
基类的Marble
以及派生的RedMarble
的串联。
DumpBag
需要进行一种“静态虚拟呼叫”。我已经开始使用以下内容实现DumpBag
:
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());
...
}
我的问题:
RedMarble.Nicknames
隐藏Marble.Nicknames
的警告(当然)。是否可以继续标记new
?答案 0 :(得分:3)
你会发现你所缺少的是一个显式的演员:
(List<string>)this.MarbleType.GetProperty("Nicknames").GetValue(null, null);
当我测试它时,这对我来说很好。
正如评论中所讨论的那样,你不应该真的使用new关键字,你最好将基类静态方法命名为其他东西,这样就没有歧义了。你毕竟控制了这一点而没有使用别人的代码。
现在,应该你这样做吗?
好吧,首先你肯定要使用泛型未定义的方法来返回类型:
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> {
}
当然,你可以做的第二件事就是让这个不是静态的,在这种情况下,属性将在Marble
中抽象,并在RedMarble
和{{中覆盖1}},然后直接在BlueMarble
中以DumpBag
直接访问,而不是使用反射。