为每个派生自动创建静态变量的副本 class

Automatically create a copy of a static variable for each derived class

我有一个带有静态变量的基 class。我想创建派生的 subclasses,它会自动拥有自己的非共享静态变量。理想情况下它看起来像这样:

class Parent
{
     Texture2D picture;
     static Texture2D pictureOrigin;

     Parent()
     {
         picture = pictureOrigin;
         /*Loading the static origin to an instance variable
         because I might want to have more pictureOrigins 
         and alternate them or perhaps change the picture
         of the instance based on a certain event, etc.*/            
     }
}

class Subclass1 : Parent
{
    Subclass1() : base()
    { }
}

class Subclass2 : Parent
{
    Subclass2() : base()
    { }
}

void main()
{
    Parent.pictureOrigin = Load("pictureForParent"); 
    Subclass1.pictureOrigin = Load("pictureForSubclass1");
    Subclass2.pictureOrigin = Load("pictureForSubclass2");
    //Then creating instances of the classes and drawing them, etc.
}

但是发生的是它们都获得了最后加载的图像 (pictureForSubclass2),因为静态变量 pictureOrigin 在它们之间共享。

最快的解决方法是手动添加新的静态变量 pictureOrigin 到每个子 class 并隐藏基础 class:

pictureOrigin 变量
class Subclass1 : Parent
{
    new static Texture2D pictureOrigin;

    Subclass1() : base()
    {
         picture = pictureOrigin;
    }
}

或者,创建抽象方法或类似方法以确保在子classes 中创建新的静态变量。但这似乎太麻烦而且不太优雅。有更好的方法吗?

你的问题设计得很糟糕。在我看来,静态变量通常是不好的做法,适当的面向对象设计可以消除使用静态成员的需要。

像这样尝试重构:

public class Parent
{
    private Texture2D texture;

    public Parent(Texture2D texture) {
        this.texture = texture;
    }

    public Texture2D Picture { get {
            return texture;
        }
    }
}

public class SubClass1 : Parent
{
    public SubClass1(Texture2D texture) : base(texture) {

    }
}

让我详细说明为什么静态是一个糟糕的选择:

  1. 您的 class 现在仅适用于单个位图。消除了为多个位图重用 class 的可能性(这是您要反对的限制)
  2. 在调用静态 setter 之前,您的 class 未处于有效状态。通常,对象一旦构造,就应该处于有效状态。如果其他人正在使用您的对象,他们必须在 class.
  3. 上静态设置位图,这对其他人来说并不明显
  4. 破坏自然垃圾收集。例如,如果您希望在收集 SubClass 的所有实例时对 Texture2D 对象进行垃圾收集,那么它不适用于您的静态设计。或者,如果您使用 oop 设计(如建议的那样),您可以根据您的用例灵活地进行垃圾收集或不进行垃圾收集。
  5. 使线程更复杂。静态是全局的,所以你需要全局互斥锁来保证线程安全。
  6. 使测试更加困难。如果你想对 class 进行单元测试,你必须确保每次测试后静态都被清除,并且你不能 运行 针对这个 class 并行进行两个单元测试.
  7. 使内存管理不灵活。如果您使用面向对象的设计,您可以选择在所有实例之间共享位图,或者为每个实例分配一个新位图。

您可以使用静态 Dictionary<Type,Texture2D>

public class Parent
{
    // Keep a table of types and default values
    protected static Dictionary<Type, Texture2D> pictureOrigin;

    static Parent()
    {
        // static ctor. initialize table
        pictureOrigin=new Dictionary<Type, Texture2D>();
    }

    internal static void SetDefaultPicture<T>(Texture2D picture)
    {
        // Set default based on type T
        Type type=typeof(T);
        pictureOrigin[type]=picture;
    }

    public Parent()
    {
        // Assign default based on this type
        Picture=pictureOrigin[this.GetType()];
    }
    public Texture2D Picture { get; set; }
}

public class SubClass1 : Parent
{
}
public class SubClass2 : Parent
{
}

用作

    static void Main(string[] args)
    {
        Texture2D picture0 = Load("pictureForParent");
        Texture2D picture1=Load("pictureFroSubClass1");
        Texture2D picture2=Load("pictureFroSubClass2");

        Parent.SetDefaultPicture<Parent>(picture0);
        Parent.SetDefaultPicture<SubClass1>(picture1);
        Parent.SetDefaultPicture<SubClass2>(picture2);            
    }

这里是一个例子的调试。它显示 SubClass1 自动用 pictureForSubClass1 初始化。

以泛型类型声明的静态成员基本上是根据 class 及其泛型声明的。 例如 Foo<Bar>.baz 不等于 Foo<Qux>.baz.

所以基本上你可以这样做:

abstract class Parent<T>
{
     Texture2D picture;
     static Texture2D pictureOrigin;

     Parent()
     {
         picture = pictureOrigin;
         /*Loading the static origin to an instance variable
         because I might want to have more pictureOrigins 
         and alternate them or perhaps change the picture
         of the instance based on a certain event, etc.*/            
     }
}

class Parent : Parent<Parent>
{
    Parent () : base()
    { }
}

class Subclass1 : Parent<Subclass1>
{
    Subclass1() : base()
    { }
}

class Subclass2 : Parent<Subclass2>
{
    Subclass2() : base()
    { }
}

void main()
{
    Parent.pictureOrigin = Load("pictureForParent"); 
    Parent<Subclass1>.pictureOrigin = Load("pictureForSubclass1");
    Parent<Subclass2>.pictureOrigin = Load("pictureForSubclass2");
}