pavelkomin
pavelkomin

Reputation: 33

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

I have a base class with a static variable. I want to create derived subclasses which will automatically have their own unshared static variable. Ideally it would look like this:

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.
}

But what happens is that they all get the last loaded image (pictureForSubclass2) because the static variable pictureOrigin is shared between them.

The quickest fix is manually adding new static variable pictureOrigin to each subclass and hiding the pictureOrigin variable of the base class:

class Subclass1 : Parent
{
    new static Texture2D pictureOrigin;

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

Alternatively, creating abstract methods or similar to ensure the creation of the new static variable in the subclasses. But it seems like too much of a hassle and not too elegant. Is there a better way of doing this?

Upvotes: 0

Views: 2322

Answers (3)

nrofis
nrofis

Reputation: 9766

A static member that declared in generic type is basically declared per class and its generic. For example Foo<Bar>.baz is not equal to Foo<Qux>.baz.

So basically you can do this:

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

Upvotes: 0

Samuel
Samuel

Reputation: 17171

Your question smells like a poor design. Static variables are generally poor practice in my opinion, and proper object-oriented design can eliminate the need to ever use static members.

Try refactoring like so:

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) {

    }
}

Let me elaborate on why static is a poor choice:

  1. Your class is now only good for a single bitmap. Eliminates the possibility to reuse a class for several bitmaps (this is the limitation you're fighting against)
  2. Your class is not in a valid state until the static setter is called. Generally objects, once constructed, should be in a valid state. It won't be obvious to others if they're using your object that they have to statically set the bitmap on the class.
  3. Breaks the natural garbage collection. For example if you wanted the Texture2D object to be garbage collected when all the instances of SubClass are collected it wouldn't work with your static design. Alternatively, if you use a oop design (like suggested) you have the flexibility to garbage collect or not depending on your use cases.
  4. Makes threading more complicated. Statics are global, so you need global mutexes to guarantee thread-safety.
  5. Makes testing more difficult. If you want to unit test the class, you have to make sure that the static is cleaned up after every test, and you couldn't run two unit tests against this class in parallel.
  6. Makes memory management inflexible. If you use object-oriented design you can choose to share bitmaps among all instances, or allocate a new bitmap for every instance.

Upvotes: 1

John Alexiou
John Alexiou

Reputation: 29244

You can do this with a static 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
{
}

to be used as

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

Here is the debug of an example. It shows that SubClass1 initialized with pictureForSubClass1 automatically.

res

Upvotes: 1

Related Questions