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

时间:2015-12-21 18:15:42

标签: c# inheritance static-variables

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

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并隐藏基类的pictureOrigin变量:

class Subclass1 : Parent
{
    new static Texture2D pictureOrigin;

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

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

3 个答案:

答案 0 :(得分:1)

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

尝试重构:

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

答案 1 :(得分:1)

您可以使用静态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

res

答案 2 :(得分:0)

以泛型类型声明的静态成员基本上是按类及其泛型声明的。 例如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");
}