【问题标题】:Using reflection to get static property value, a concatenation of derived and base class使用反射获取静态属性值,派生类和基类的串联
【发布时间】:2012-05-02 04:59:12
【问题描述】:

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

不幸的是,除了 Marble in the Bag 之外还有其他东西,所以泛型在这里帮不了我。

// 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似乎有效吗?

【问题讨论】:

    标签: c# reflection


    【解决方案1】:

    您会发现您所缺少的只是 显式 演员表:

    (List&lt;string&gt;)this.MarbleType.GetProperty("Nicknames").GetValue(null, null);

    当我测试它时,这对我来说很好。

    正如 cmets 中所讨论的,不,您不应该真正使用 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 中被覆盖,然后只是在DumpBag 中直接以Nicknames 访问,而不是使用反射。

    【讨论】:

    • 除了重命名Marble.Nicknames -> Marble.BaseNicknames,你的代码示例和我的有什么不同吗?连接就像你在RedMarble.Nicknames 中拥有的一样。
    • 我对反射的使用来自于Bag本身不知道它在处理什么类型的Marbles,所以它使用虚拟属性来获取Type,并且然后反射以从该类型获取静态属性。
    • 一定错过了你的代码的一部分——注意你有Marble.Names而不是Marble.Nicknames,这让我很失望。要回答您问题的第 2 部分,请不要将其标记为新的,这不是真正的继承。
    • 啊,我很抱歉 - 那应该是昵称。固定。
    猜你喜欢
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 2011-08-25
    • 1970-01-01
    • 2017-11-05
    相关资源
    最近更新 更多