简体   繁体   English

当属性位于基类中时,如何访问子类中的静态属性?

[英]How can I access a static property in a subclass when the property is located in a base class?

Let's say I have: 比方说我有:

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");
    }

}

If I just do this in the calling code: 如果我只是在调用代码中执行此操作:

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

I get: 我明白了:

  • Company A 公司A.

Whereas if I do: 如果我这样做:

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

I get (the desired result): 我得到了(期望的结果):

  • Company A 公司A.
  • Company B 公司B.

Edit: After reading the responses I understand that this won't work. 编辑:阅读回复后我明白这不会奏效。

What I want in my production code is a list of values that is common to the type of object and I want to dynamically add different values to that list of strings based on the subtype. 我在生产代码中想要的是一个对象类型共有的值列表,我想根据子类型动态地将不同的值添加到该字符串列表中。 (The context is LDAP - all entries have objectClass=top and all user-objects have objectClass=user,top,organizationPerson,person). (上下文是LDAP - 所有条目都有objectClass = top,所有用户对象都有objectClass = user,top,organizationPerson,person)。 Guess I have to use an interface or different lists in each subclass or something if no one has a better suggestion? 猜猜如果没有人有更好的建议,我必须在每个子类中使用一个接口或不同的列表?

For one thing, accessing Banana.Suppliers is misleading. 首先,访问Banana.Suppliers是误导性的。 It will always yield the same result as accessing Apple.Suppliers etc - you've got a single collection of suppliers. 它总会产生与访问Apple.Suppliers等相同的结果 - 您只有一个供应商集合。

Basically any time you access Banana.Suppliers the compiler emits a call to Fruit.Suppliers : that's why just calling Banana.Suppliers isn't triggering the static constructor which adds the banana supplier. 基本上Banana.Suppliers访问Banana.Suppliers ,编译器都会调用Fruit.Suppliers :这就是为什么只调用Banana.Suppliers不会触发添加香蕉供应商的静态构造函数。

The reason you only see the suppliers added in the static constructor for bananas after you've created a banana is that that forces the static constructor to run. 您在创建香蕉后只看到香蕉静态构造函数中添加的供应商的原因是强制静态构造函数运行。 You could do anything else that forced the static initializer to run, and you'd get the same results. 你可以做任何其他迫使静态初始化程序运行的东西,你会得到相同的结果。 One example would be calling a static method within Banana itself. 一个例子是在Banana调用静态方法。

Now, I strongly suspect that you've got a significant problem in that you'll be using the same suppliers for all types. 现在,我强烈怀疑您遇到了一个重大问题,即您将使用所有类型的相同供应商。 Obviously this isn't your real code, and the best solution will depend on what you want your real code to do. 显然,这不是您的真实代码,最佳解决方案将取决于您希望实际代码执行的操作。 Generics can give you effectively "per type" static variables using type arguments : Foo<Banana>.StaticProperty and Foo<Apple>.StaticProperty will really be different, assuming StaticProperty is declared in Foo<T> . 泛型可以使用类型参数为您提供有效的“每类型”静态变量: Foo<Banana>.StaticPropertyFoo<Apple>.StaticProperty将真的不同,假设在Foo<T>声明了StaticProperty

EDIT: With regards to your edit, I would suggest avoiding using statics here. 编辑:关于你的编辑,我建议避免在这里使用静态。 Possibly create a factory for each type (implementing an interface which may be generic). 可能为每种类型创建一个工厂(实现可能是通用的接口)。 Note that you may well be able to avoid creating a separate factory type for each subtype, if you can create an appropriate instance with all the relevant items for each type. 请注意,如果可以为每种类型创建包含所有相关项的相应实例,则可以避免为每个子类型创建单独的工厂类型。

We'd really need to see more of an example to say for sure, but in general I find that the less static data you have, the more testable your design will be and the less you'll run into problems like this :) 我们确实需要看到更多可以肯定的例子,但总的来说,我发现你拥有的静态数据越少,你的设计就越可测试,你遇到的问题就越少:)

The results you are seeing are caused by the way that static constructors work. 您看到的结果是由静态构造函数的工作方式引起的。 The CLR does not actually execute the static constructor util the first instance is used, which is why you only get the desired results in your second example. CLR实际上并不执行使用第一个实例的静态构造函数util,这就是为什么你只在第二个例子中得到所需的结果。 See MSDN for more info. 有关详细信息,请参阅MSDN

The cuase of this is quite easily explainable, in fact. 事实上,这很容易解释。 When you get Banana.Suppliers , you're actually just referencing Fruit.Suppliers - the compiler ends up resolving to the Fruit class in this case because of the way inheritance works (nothing is defined in the Banana class. Thus, your static constructor for Banana is not called in the first example because you have technically not yet referenced the class in any way. This is of course why you are missing the "Company B" item in the first result. 当你得到Banana.Suppliers ,你实际上只是引用Fruit.Suppliers在这种情况下编译器最终解析为Fruit类,因为继承的工作方式(在Banana类中没有定义。因此,你的静态构造函数为在第一个例子中没有调用Banana ,因为你在技术上还没有以任何方式引用该类。这当然是你在第一个结果中缺少“公司B”项目的原因。

The problem here is a design issue. 这里的问题是设计问题。 I'm not sure exactly what your intentions are here, but if you do in fact want a property in the Fruit class to store the list of all suppliers, then you need to initialise the list completely within the static constructor for the Fruit class. 我不确定你的意图究竟是什么,但如果你确实想要Fruit类中的一个属性来存储所有供应商的列表,那么你需要在Fruit类的静态构造函数中完全初始化列表。 In general, however, I would think you'd want a separate dataset class or such for this purpose. 但是,一般情况下,我认为您需要一个单独的数据集类或此类目的。 Static properties is probably not the way to approach this design feature. 静态属性可能不是接近此设计功能的方法。

Accessing Banana.Suppliers gets compiled to an access of Fruit.Suppliers ... which means that effectively your code is not actually touching the Banana class, which means that .NET has no reason to execute the static constructor of Banana . 访问Banana.Suppliers被编译为访问Fruit.Suppliers ...这意味着你的代码实际上并没有触及Banana类,这意味着.NET没有理由执行Banana的静态构造函数。

If you did pretty much anything else with the Banana class (such as you creating an instance of it for example), the Banana static constructor runs. 如果您使用Banana类做了很多其他事情(例如您创建了它的实例),那么Banana静态构造函数就会运行。

A static constructor does not behave like an instance constructor (they're not called explicitly). 静态构造函数的行为与实例构造函数不同(它们未被显式调用)。 You have to access a property that's actually on the Banana class before it is constructed. 在构造之前,您必须访问实际上在Banana类上的属性。 You're trying to apply some principles of object orientation to static behavior on classes. 您试图将一些面向对象的原则应用于类上的静态行为。 They're not equatable, and doing this is going to lead you down a route will ultimately lead you to despair. 他们不是平等的,这样做会导致你走上一条路,最终会让你绝望。

This code: 这段代码:

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

Is the exact equivalent to this code: 是否与此代码完全等效:

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

So the static constructor on Banana is never called, because it is never needed. 所以Banana上的静态构造函数永远不会被调用,因为它永远不需要。 The below code demonstrates how making a call to a static member of fruit causes its static constructor to be called, yielding the results you're looking for. 下面的代码演示了如何调用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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM