【问题标题】:Making a superclass have a static variable that's different for each subclass in c#使超类具有对于c#中的每个子类都不同的静态变量
【发布时间】:2010-12-23 00:31:29
【问题描述】:

在子类中没有任何代码,我希望抽象类为每个子类提供不同的静态变量副本。在 C# 中

abstract class ClassA
{
    static string theValue;

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

和(例如):

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

我目前的解决方案是这样的:

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

虽然这可以正常工作,但我想知道是否有更优雅或内置的方法可以做到这一点?

这类似于Can I have different copies of a static variable for each different type of inheriting class,但我无法控制子类

【问题讨论】:

  • 你可以通过破解 Dictionary&lt;Type,...&gt; 并调用 GetType() 来做到这一点,但这太可怕了......
  • 对于虚拟/抽象静态成员会很好。见dotnetrocks.com/text/0448/index9.html>(搜索“虚拟静态成员”)
  • 为什么不让它不是静态的?
  • BlackTigerX,ClassB 的每个实例的值必须相同 - 但与 ClassC 的值不同
  • 使用基类字典中的类型将起作用。感谢您的想法,我不认为这是使其工作的一种方式。

标签: c# inheritance static-variables


【解决方案1】:

还有一种更优雅的方式。您可以利用泛型基类中的静态对于不同类型的每个派生类都不同的事实

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

对于每个子类,静态 int x 对于每个唯一的 T 都是唯一的 让我们派生两个子类,我们在基类中使用子类的名称作为泛型 T。

public class ChildA: BaseClass<ChildA>
{
}

public class ChildB : BaseClass<ChildB>
{
}

现在静态 MyProperty 对于 ChildA 和 ChildB 都是唯一的

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

【讨论】:

  • 不,这是错误的。 TA 和 TB MyProperty 现在都是 4。
  • @TheSoftwareJedi。错误的?不是这样,我的朋友,看来您不了解抽象泛型类中静态的实现。您能否创建一个快速控制台应用程序,复制我上面的代码,然后运行它。那么请收回您的评论、您的反对票,或者考虑支持投票,因为这是对所提出问题的最优雅的回答。
  • 你是对的,我很抱歉。我忽略了泛型!!我对你的答案做了一个小修改,只是为了投票。
  • 但是,OP 不能使用它,因为“我无法控制子类”
  • 是的,抽象泛型中静态的这个小“功能”花费了我一天调试应用程序的时间。我真的很惊讶静态在子类中是独一无二的。这当然不是我所期待的
【解决方案2】:

虽然这可以正常工作,但我想知道是否有更优雅或内置的方法可以做到这一点?

实际上并没有内置的方法来执行此操作,因为您在这里有点违反基本的 OO 原则。您的基类不应该了解传统面向对象理论中的子类。

话虽如此,如果您必须这样做,您的实现可能与您将获得的一样好,除非您可以直接向子类添加一些其他信息。如果您需要对此进行控制,并且无法更改子类,这可能是您最好的方法。

【讨论】:

  • 对于那些偶然发现此问题的人,请务必在下面查看@jimbob 的答案。
【解决方案3】:

这与您所要求的略有不同,但可能完成相同的事情。

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

【讨论】:

  • 这是显而易见的 + 最佳方式 - 不幸的是我无法更改 B 类和 C 类
【解决方案4】:

有一个替代解决方案可能会或可能不会比您的解决方案更好,具体取决于用例:

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

这种方法用于EqualityComparer&lt;T&gt;.Default。当然,它不适用于这个问题。您真的应该考虑将 GetValue 抽象化并在每个派生类中覆盖它。

【讨论】:

  • @enorl76 这个问题很老,所以我不记得实际的上下文,但我认为这种方法不需要覆盖 GetValue。我回答的最后一句话只是对正确方法的评论,而不是解决方案的一部分。
【解决方案5】:

这个怎么样?



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

它对我有用。 有接口会更好。

【讨论】:

  • 注意解释代码是为了他人的利益做了什么,没有解释的代码转储不会满足 SO 用户:)
  • 不,这永远行不通。根据 VM 何时看到类型,即调用静态构造函数的时间,因此“myVariable”将包含 last-ran-static-constructor 的值。更糟糕的是,最后一个构造函数是谁将是不确定的。
【解决方案6】:

简单的解决方案:只需使用“新”一词。

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

结果:

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

或者你可以使用属性:

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

或函数(但记得在变量和函数中添加“new”):

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

或者你可以使用私有变量(你不需要使用“new”)来获取和设置函数:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-20
    • 2014-11-22
    • 2018-07-13
    • 2020-11-09
    相关资源
    最近更新 更多