English 中文(简体)
Making a superclass have a static variable that s different for each subclass in c#
原标题:

Without any code in the subclasses, I d like an abstract class to have a different copy of a static variable for each subclass. In C#

abstract class ClassA
{
    static string theValue;

    // just to demonstrate
    public string GetValue()
    {
        return theValue;
    }
    ...
}
class ClassB : ClassA { }
class ClassC : ClassA { }

and (for example):

(new ClassB()).GetValue(); // returns "Banana"
(new ClassC()).GetValue(); // returns "Coconut"

My current solution is this:

abstract class ClassA
{
    static Dictionary<Type, string> theValue;
    public string GetValue()
    {
        return theValue[this.GetType()];
    }
    ...
}

While this works fine, I m wondering if there s a more elegant or built-in way of doing this?

This is similar to Can I have different copies of a static variable for each different type of inheriting class, but I have no control over the subclasses

最佳回答

While this works fine, I m wondering if there s a more elegant or built-in way of doing this?

There isn t really a built-in way of doing this, as you re kind of violating basic OO principles here. Your base class should have no knowledge of subclasses in traditional object oriented theory.

That being said, if you must do this, your implementation is probably about as good as you re going to get, unless you can add some other info to the subclasses directly. If you need to control this, and you can t change subclasses, this will probably be your best approach.

问题回答

There is a more elegant way. You can exploit the fact that statics in a generic base class are different for each derived class of a different type

public abstract class BaseClass<T> where T : class
{
    public static int x = 6;
    public int MyProperty { get => x; set => x = value; }
}

For each child class, the static int x will be unique for each unique T Lets derive two child classes, and we use the name of the child class as the generic T in the base class.

public class ChildA: BaseClass<ChildA>
{
}

public class ChildB : BaseClass<ChildB>
{
}

Now the static MyProperty is unique for both ChildA and ChildB

var TA = new ChildA();
TA.MyProperty = 8;
var TB = new ChildB();
TB.MyProperty = 4;

This is a little different than what you re asking for, but perhaps accomplishes the same thing.

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((new B()).theValue);
            Console.WriteLine((new C()).theValue);
            Console.ReadKey();
        }
    }

    public abstract class A
    {
        public readonly string theValue;

        protected A(string s)
        {
            theValue = s;
        }
    }

    public class B : A
    {
        public B(): base("Banana")
        {
        }
    }

    public class C : A
    {
        public C(): base("Coconut")
        {
        }
    }

There s an alternative solution which might or might not be better than yours, depending on the use case:

abstract class ClassA
{
    private static class InternalClass<T> {
        public static string Value;
    }
    public string GetValue()
    {
        return (string)typeof(InternalClass<>)
              .MakeGenericType(GetType())
              .GetField("Value", BindingFlags.Public | BindingFlags.Static)
              .GetValue(null);
    }
}

This approach is used in EqualityComparer<T>.Default. Of course, it s not used for this problem. You should really consider making GetValue abstract and override it in each derived class.

What about this?



    class Base {
    protected static SomeObjectType myVariable;

    protected void doSomething()
    {
    Console.WriteLine( myVariable.SomeProperty );
    }
    }

    class AAA : Base
    {
    static AAA()
    {
    myVariable = new SomeObjectType();
    myVariable.SomeProperty = "A";
    }
    }

    class BBB : Base
    {
    static BBB()
    {
    myVariable = new SomeObjectType();
    myVariable.SomeProperty = "B";
    }
    }

It works for me. Would be even nicer with Interface.

Simple solution: just use word "new".

public abstract class AbstractClass
{
    public static int Variable;
}

public class RealizationA : AbstractClass
{
    public new static int Variable;
}

public class RealizationB : AbstractClass
{
    public new static int Variable;
}

And the result:

AbstractClass.Variable = 1;
RealizationA.Variable = 2;
RealizationB.Variable = 3;
Console.WriteLine(AbstractClass.Variable); //1
Console.WriteLine(RealizationA.Variable); //2
Console.WriteLine(RealizationB.Variable); //3

or you can use property:

//in abstract class
public static int Variable {get; set;}
//in child class
public static new int Variable {get; set;}

or function (but remember to add "new" to both variable and function):

//in abstract class
protected static int Variable;
public static int GetVariable() { return Variable; }
public static void SetVariable(int v) { Variable = v; }
//in child class
protected new static int Variable;
public static new int GetVariable() { return Variable; }
public static new void SetVariable(int v) { Variable = v; }

or you can use private variables (you don t need to use "new") with functions to get and set:

//in abstract class
private static int Variable;
//get and set methods
//in child class
private static int Variable;
//get and set methods




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签