C# 当静态属性位于基类中时,如何访问子类中的静态属性?
假设我有:C# 当静态属性位于基类中时,如何访问子类中的静态属性?,c#,inheritance,C#,Inheritance,假设我有: 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 {
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");
}
}
我得到:
- A公司
Banana b = new Banana();
foreach(String supplier in Banana.Suppliers)
Console.WriteLine(supplier);
我得到(期望的结果):
- A公司
- B公司
在我的生产代码中,我想要的是一个对象类型通用的值列表,并且我想要根据子类型动态地向该字符串列表添加不同的值。(上下文是LDAP-所有条目的objectClass=top,所有用户对象的objectClass=user、top、organizationPerson、person)。如果没有人有更好的建议,我想我必须在每个子类中使用一个接口或不同的列表或其他什么?您看到的结果是由静态构造函数的工作方式造成的。在使用第一个实例时,CLR实际上并不执行静态构造函数,这就是为什么在第二个示例中只得到所需的结果。有关更多信息,请参阅。首先,访问
Banana.Suppliers
会产生误导。它总是会产生与访问苹果供应商相同的结果-你有一个单一的供应商集合
基本上,每当您访问Banana.Suppliers
时,编译器都会发出对Fruit.Suppliers
的调用:这就是为什么只调用Banana.Suppliers
并不会触发添加香蕉供应商的静态构造函数
创建香蕉后,您只能在香蕉的静态构造函数中看到添加的供应商,这是因为这会强制静态构造函数运行。您可以执行任何其他强制静态初始值设定项运行的操作,您将得到相同的结果。一个例子是在Banana
本身中调用静态方法
现在,我强烈怀疑你有一个重大的问题,你将使用相同的供应商为所有类型。显然,这不是您真正的代码,最好的解决方案将取决于您希望真正的代码做什么。泛型可以使用类型参数有效地为您提供“每类型”静态变量:Foo.StaticProperty
和Foo.StaticProperty
将确实不同,假设StaticProperty
在Foo
中声明
编辑:关于你的编辑,我建议避免在这里使用静态。可能为每种类型创建一个工厂(实现一个可能是泛型的接口)。请注意,如果可以为每个子类型创建一个包含所有相关项的适当实例,则可以避免为每个子类型创建单独的factory类型
我们确实需要看更多的例子来确定,但一般来说,我发现静态数据越少,设计的可测试性就越高,遇到这样的问题也就越少:)事实上,这种情况很容易解释。当您得到
Banana.Suppliers
时,实际上您只是引用了Fruit.Suppliers
——由于继承的工作方式,编译器最终解析为Fruit
类(在Banana
类中没有定义任何内容。因此,在第一个示例中没有调用Banana
的静态构造函数,因为您在技术上还没有以任何方式引用该类。这当然是您在第一个结果中缺少“Company B”项的原因
这里的问题是一个设计问题。我不确定您的意图到底是什么,但如果您确实希望
Fruit
类中的一个属性来存储所有供应商的列表,那么您需要在Fruit
类的静态构造函数中完全初始化该列表。但是,一般来说,我认为您应该为此需要一个单独的数据集类或类似的类。静态属性可能不是实现此设计功能的方法。访问Banana。供应商被编译为访问Fruit.Suppliers
…这意味着您的代码实际上没有触及Banana
类,这意味着NET没有理由执行香蕉的静态构造函数
如果您对Banana
类执行了几乎所有其他操作(例如,您创建了它的实例),那么Banana
静态构造函数将运行。静态构造函数的行为与实例构造函数不同(它们没有显式调用)。在构建香蕉类之前,您必须访问香蕉类上实际存在的属性。您试图将一些面向对象的原则应用于类上的静态行为。这些原则是不平等的,这样做会使您走上一条最终会让您绝望的路
此代码:
foreach(String supplier in Banana.Suppliers)
Console.WriteLine(supplier);
完全等同于此代码:
foreach(String supplier in Fruit.Suppliers)
Console.WriteLine(supplier);
因此,香蕉上的静态构造函数永远不会被调用,因为它从来都不需要。下面的代码演示了调用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已经指出的那样,这不会像我预期的那样起作用,因为只有一个静态的水果列表。我想我不是唯一一个有点困惑的人…;-)是的,我花了太长的时间来撰写我的答案。但是我留下了它,因为底部的示例演示了另一种强制调用静态构造函数的方法。请参阅我的编辑以了解生产代码环境的解释。更有意义…关于如何实现这一点,有什么想法吗?是我Jon,我误读了,或者是你编辑的maybee,但是起初我不认为你提到这与他没有触发Bannana上的静态构造函数有关。不管怎么说,现在已经很清楚了,所以我+1@Josh:Righto-谢谢你的解释:)(这很可能是一个编辑。)@antirysm:我回家后会看看。你应该为我提出一个新问题
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);