如何为每个子类继承具有唯一值的静态属性?

时间:2013-02-09 09:11:23

标签: c# inheritance

我有一系列对象,让我们称之为建筑物,每个对象共享某些属于该建筑物的静态属性,但每个建筑物都有不同的属性,例如价格。我认为实现这个的最好方法是创建一个带有共享价格属性的抽象超类,并在每个子类中设置值,但我无法弄清楚如何使其工作。这是我尝试过的一个例子:

using System;
public abstract class Buildings
{
   internal static int price;
   internal static int turnsToMake;
}
using System;
public class Walls : Buildings
{
    public Walls()
    {
        price = 200;
        turnsToMake = 5;
    }
}

这适用于构造,但如果我想在创建它之前检查价格(检查玩家是否有足够的钱),那么它只返回一个空值。我确信这是一个非常简单的修复,但我无法弄清楚。有什么帮助吗?

3 个答案:

答案 0 :(得分:7)

有一个"斑驳的"但值得考虑的简单解决方案。如果将基类定义为Generic类,并且在派生类中将T设置为类本身,它将起作用。

这是因为.NET为每个新定义静态定义了一种新类型。

例如:

class Base<T>
{
    public static int Counter { get; set; }

    public Base()
    {
    }
}

class DerivedA : Base<DerivedA>
{
    public DerivedA()
    {
    }
}

class DerivedB : Base<DerivedB>
{
    public DerivedB()
    {
    }
}

class Program
{
    static void Main(string[] args)
    {

        DerivedA.Counter = 4;
        DerivedB.Counter = 7;

        Console.WriteLine(DerivedA.Counter.ToString()); // Prints 4
        Console.WriteLine(DerivedB.Counter.ToString()); // Prints 7

        Console.ReadLine();
    }
}

答案 1 :(得分:5)

请勿使用static。 Static表示Building的所有实例都具有相同的值。派生类不会继承自己的静态副本;但总是会修改基类静态。在你的设计中,只有一个价格和turnToMake值。

这应该适合你:

public abstract class Buildings
{
  internal int price;
  internal int turnsToMake;
}

但是,现在大多数人不喜欢使用字段而更喜欢属性。

public abstract class Buildings
{
  internal int Price { get; set; }
  internal int TurnsToMake { get; set; }
}

答案 2 :(得分:1)

  

我想在创建之前检查价格[...]

我想你是如何进入静态领域的;但是,静态和虚拟行为无法组合。也就是说,您必须为每个子类重新声明静态字段。否则,所有子类共享完全相同的字段并覆盖彼此的值。

另一个解决方案是使用.NET(4或更高版本)框架类库中的Lazy<T, TMetadata> type

public class Cost
{
    public int Price { get; set; }
    public int TurnsToMake { get; set; }
}

var lazyBuildings = new Lazy<Buildings, Cost>(
        valueFactory: () => new Walls(),
        metadata: new Cost { Price = 200, TurnsToMake = 5 });

if (lazyBuildings.Metadata.Price < …)
{
    var buildings = lazyBuildings.Value;
}

也就是说,元数据(.Metadata)现在位于实际类型(BuildingsWalls)之外,可用于决定您是否确实要构建实例( .Value)。

(多亏了多态,您可以拥有这些“懒惰工厂”的整个集合,并根据每个工厂的元数据找到要实例化的建筑类型。)