【问题标题】:How can I access a static property in a subclass when the property is located in a base class?当属性位于基类中时,如何访问子类中的静态属性?
【发布时间】:2009-06-15 12:49:34
【问题描述】:

假设我有:

public class Fruit
{

    public static List<String> Suppliers { get; protected set; }

    static Fruit()
    {
        Suppliers = new List<String>();
        Suppliers.Add("Company A");
    }

}

public class Banana : Fruit
{

    static Banana()
    {
        Suppliers.Add("Company B");
    }

}

如果我只是在调用代码中这样做:

foreach(String supplier in Banana.Suppliers)
    Console.WriteLine(supplier);

我明白了:

  • A公司

如果我这样做:

Banana b = new Banana();
foreach(String supplier in Banana.Suppliers)
    Console.WriteLine(supplier);

我得到(想要的结果):

  • A公司
  • 公司B

编辑: 阅读回复后,我知道这是行不通的。

我在生产代码中想要的是对象类型共有的值列表,我想根据子类型动态地将不同的值添加到该字符串列表中。 (上下文是 LDAP - 所有条目都有 objectClass=top 并且所有用户对象都有 objectClass=user,top,organizationPerson,person)。如果没有人有更好的建议,我猜我必须在每个子类中使用一个接口或不同的列表或其他东西?

【问题讨论】:

  • 您应该为您的编辑提出一个新问题。
  • @Josh - 我认为上下文仍然是相同的,我只是认为我认为尝试做我正在尝试的事情是有正当理由的......
  • 我不认为@Josh 质疑您的问题的有效性,只是如果您将编辑拆分为自己的问题,带有适当的标题并且没有原始上下文的包袱。

标签: c# inheritance


【解决方案1】:

一方面,访问Banana.Suppliers 具有误导性。它总是会产生与访问 Apple.Suppliers 等相同的结果 - 你有一个 single 供应商集合。

基本上,每当您访问Banana.Suppliers 时,编译器都会发出对Fruit.Suppliers 的调用:这就是为什么只调用Banana.Suppliers 不会触发添加香蕉供应商的静态构造函数。

创建香蕉后,您只能在香蕉的静态构造函数中看到添加的供应商,这是因为这会强制静态构造函数运行。您可以执行任何其他强制静态初始化程序运行的操作,并且您会得到相同的结果。一个示例是在 Banana 本身内调用静态方法。

现在,我强烈怀疑您遇到了一个重大问题,即您将为所有类型使用相同的供应商。显然这不是您的真实代码,最佳解决方案将取决于您希望您的真实代码做什么。泛型可以使用类型参数有效地为您提供“每个类型”的静态变量:Foo&lt;Banana&gt;.StaticPropertyFoo&lt;Apple&gt;.StaticProperty 确实会有所不同,假设 StaticPropertyFoo&lt;T&gt; 中声明。

编辑:关于您的编辑,我建议避免在此处使用静态。可能为每种类型创建一个工厂(实现一个可能是通用的接口)。请注意,如果您可以为每种类型创建一个包含所有相关项目的适当实例,那么您很可能可以避免为每个子类型创建单独的工厂 type

我们确实需要看到更多的例子才能确定,但​​总的来说,我发现您拥有的静态数据越少,您的设计就越可测试,遇到此类问题的可能性就越小:)

【讨论】:

  • 有关生产代码环境的说明,请参阅我的编辑。更有意义...关于如何实现它的任何想法?
  • 是我 Jon,我看错了或者你编辑了,但起初我不认为你提到这与他没有触发 Bannana 上的静态构造函数有关。无论如何,现在它很清楚,所以我 +1
  • @Josh:Righto - 感谢您的解释 :)(很可能是一个编辑。)@antirysm:我回家时会看。
【解决方案2】:

您看到的结果是由静态构造函数的工作方式引起的。 CLR 在使用第一个实例时实际上并不执行静态构造函数,这就是为什么您在第二个示例中只能获得所需结果的原因。请参阅MSDN 了解更多信息。

【讨论】:

    【解决方案3】:

    事实上,这个原因很容易解释。当你得到Banana.Suppliers 时,你实际上只是在引用Fruit.Suppliers - 在这种情况下,由于继承的工作方式,编译器最终解析为Fruit 类(Banana 类中没有定义任何内容。因此,在第一个示例中未调用 Banana 的静态构造函数,因为从技术上讲,您尚未以任何方式引用该类。这当然是您在第一个结果中缺少“公司 B”项的原因。

    这里的问题是设计问题。我不确定您的意图到底是什么,但如果您确实想要 Fruit 类中的一个属性来存储 所有 供应商的列表,那么您需要完全初始化该列表在Fruit 类的静态构造函数中。但是,总的来说,我认为您需要一个单独的数据集类或类似的目的。静态属性可能不是实现此设计功能的方法。

    【讨论】:

      【解决方案4】:

      访问Banana.Suppliers 被编译为Fruit.Suppliers 的访问...这意味着实际上您的代码实际上并没有触及Banana 类,这意味着.NET 没有理由执行@ 的静态构造函数987654324@.

      如果您对 Banana 类做了很多其他事情(例如创建它的实例),Banana 静态构造函数就会运行。

      【讨论】:

        【解决方案5】:

        静态构造函数的行为不像实例构造函数(它们没有被显式调用)。在构建 Banana 类之前,您必须访问该属性。您正在尝试将一些面向对象的原则应用于类的静态行为。它们是不相等的,这样做会导致你走上一条最终会导致你绝望的路线。

        这段代码:

        foreach(String supplier in Banana.Suppliers)
            Console.WriteLine(supplier);
        

        是否完全等同于这段代码:

        foreach(String supplier in Fruit.Suppliers)
            Console.WriteLine(supplier);
        

        所以 Banana 上的静态构造函数永远不会被调用,因为它永远不需要。下面的代码演示了调用fruit的静态成员如何导致调用其静态构造函数,从而产生您正在寻找的结果。

        public class Banana : Fruit
        {
            static Banana()
            {
                Suppliers.Add("Company B");
            }
            public static void Foo()
            {
        
            }
        }
        
        // ...
        Banana.Foo();
        foreach (var supplier in Banana.Suppliers)
            Console.WriteLine(supplier);
        

        【讨论】:

        • 实际上,正如 Jon Skeet 已经指出的那样,这不会像我预期的那样工作,因为只有一个静态的水果列表。猜猜我不是唯一一个有点困惑的人...... ;-)
        • 是的,我写答案的时间太长了。不过,我留下了它,因为底部的示例演示了另一种强制调用静态构造函数的方法。
        猜你喜欢
        • 1970-01-01
        • 2012-10-30
        • 1970-01-01
        • 1970-01-01
        • 2018-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-01
        相关资源
        最近更新 更多