静态变量是类级实例变量吗?

3
简单问题:
静态变量是“类实例变量”还是“类变量”?
知道“类实例变量”是为每个定义它的类和子类定义的变量。 而“类变量”是全局变量,适用于定义它的所有子类,包括它本身。
编辑:我知道我正在让很多C#-ish的人感到难受,因为我使用了类实例这个术语,好像一个类是某些元类的实例。这极大地简化了我的问题。虽然如果考虑到VM肯定有一个表示每个类的工件(包含方法字典、实例大小、超类等),这并不完全错误。谢谢。
3个回答

9

静态变量“属于”类型 - 它们不是实例变量。

也就是说,它们在类型的 所有 实例之间共享,包括 通用 闭合构造类型。

唯一的例外是使用 ThreadStatic 修饰的静态变量,使变量在线程内唯一。


2
值得注意的是,泛型意味着静态属于考虑了泛型参数的类型。 - Adam Houldsworth
1
不清楚的踩,顺便说一句,“可能更正确的说法是:‘静态属于一种类型’”。 - Tigran
只要它们没有被装饰为“ThreadStatic”,@KamilLach。 - Oded
@Oded 他们本来可以是类的实例变量。请看我的编辑。 - mathk
@mathk:这是错误的假设。实例 意味着某个指定类型的对象。静态 不是 实例的一部分,而是类型本身的一部分。 - Tigran
显示剩余4条评论

4
静态变量的作用范围是在给定 AppDomain 类型内。它们也可以在线程间共享,除非使用了 ThreadStaticAttribute,这时它们就成为每个线程的变量。
类成员显然是针对类的一个实例进行作用域限制,但不是派生类的“全局”变量。根据访问修饰符,成员可能对派生实例可见。
有泛型参数的类具有每个闭合泛型类型的静态变量:
class MyClass<T>
{
   public static string Name;
}

因此,MyClass<int>将拥有自己的Name副本,而MyClass<string>将拥有不同的副本。


从您的答案选择来看,似乎您想要每个派生类都有一个静态变量?

您可以使用上面提到的泛型规则进行欺骗:

class Program
{
    static void Main(string[] args)
    {
        Derived1.WhatClassAmI = "Derived1";
        Derived2.WhatClassAmI = "Derived2";

        Console.WriteLine(Derived1.WhatClassAmI); // "Derived1"
        Console.WriteLine(Derived2.WhatClassAmI); // "Derived2"

        Console.WriteLine(BaseClass<Derived1>.WhatClassAmI); // "Derived1"
        Console.WriteLine(BaseClass<Derived2>.WhatClassAmI); // "Derived2"
        Console.Read();
    }

    class BaseClass<T> where T : BaseClass<T>
    {
        public static string WhatClassAmI = "BaseClass";
    }

    class Derived1 : BaseClass<Derived1>
    {
    }

    class Derived2 : BaseClass<Derived2>
    {
    }
}

他们使用“相同”的静态变量,但由于类型闭包,每个变量都有自己的值。

很好知道,无论如何这是完全合理的,因为具有不同类型参数的通用类的每个实例将产生不同类型的对象。 - mathk
有趣的解决方案,尽管我并不是很喜欢它,因为它不太明显发生了什么。我不想让跟在我后面维护我的代码的人感到困惑。所以我决定添加一个抽象属性,并在每个子类中“重新定义”一个静态变量。 - mathk
@mathk 我个人绝不建议使用这种解决方案,它是一个巨大的代码异味。如果我知道你想要实现什么,我可以提供更合适的解决方案,但目前为止,你的问题都不是很清楚。 - Adam Houldsworth

1

它们是类变量。 在C#中没有像Smalltalk类实例变量这样的东西。也就是说,没有一种定义变量的方法,该变量在类的所有实例中都是共同的,但其子类具有不同的值。

为了获得“类似”的行为,但缺点是只有在创建类的实例后才能访问类实例变量,我做了类似于这样的事情:

public class BaseClass
{
    private static Dictionary<Type, object> ClassInstVarsDict = new Dictionary<Type, object>();

    public object ClassInstVar
    {
        get
        {
            object result;
            if (ClassInstVarsDict.TryGetValue(this.GetType(), out result))
                return result;
            else
                return null;
        }
        set
        {
            ClassInstVarsDict[this.GetType()] = value;
        }
    }
}

public class DerivedClass1 : BaseClass
{
}

public class DerivedClass2 : BaseClass
{
}

谢谢您的建议。还有一个缺点是,ClassInstVar 只能是实例属性,不能是类属性(“也就是静态属性”)。 - mathk
@mathk 现在我可能有点明白你想要什么了,我已经修改了我的答案并提供了另一种选择。 - Adam Houldsworth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接