使用反射获取静态属性值,即派生类和基类的串联

本文关键字:派生 基类 反射 获取 静态 属性 | 更新日期: 2023-09-27 18:32:55

我将尽力在这里解释我的愿景。这是一个非常蹩脚的虚构例子。我有几种不同类型的Bag,它们都有自己的特殊类型的Marble。 每种类型的Marble都有自己的昵称集(string(。

不幸的是,除了袋子里的大理石之外还有其他东西,所以泛型在这里对我没有帮助。

// 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类型,而与任何实际实例无关。它获得Marble基类的Nicknames的串联,以及派生的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());
    ...
}

我的问题:

  1. 这是理智的吗?希望我已经(或者我可以(解释我为什么走这条路的理由。
  2. 我收到警告(当然(RedMarble.Nicknames隐藏了Marble.Nicknames.继续将其标记为new似乎有效吗?

使用反射获取静态属性值,即派生类和基类的串联

你会发现

你缺少的只是一个明确的强制转换:

(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中抽象,并在RedMarbleBlueMarble中被覆盖,然后只是直接以Nicknames访问DumpBag而不是使用反射。