适用于泛型类中的静态字段

本文关键字:静态 字段 泛型类 适用于 | 更新日期: 2023-09-27 18:05:07

给定泛型类型为每个类型组合创建静态字段的单独实例,如果我想要跨所有类型拥有静态字段,那么使用这种模式有效吗?

public class BaseClass
{
    public static int P = 0;
}
public class ChildClass<T> : BaseClass
{
    public static int Q = 0;
    public void Inc()
    {
        // ChildClass<int> will have a different "Q" than ChildClass<double> 
        Interlocked.Increment(ref Q); 
        // all types of ChildClass will increment the same P
        Interlocked.Increment(ref P); 
    }
}

这种方法有什么不安全的地方吗?我的玩具示例工作,但我只是想确保没有可怕的副作用,线程后果等:)

适用于泛型类中的静态字段

您可以使用Interlocked。增加更多线程安全的代码。

public void Inc()
{
    Interlocked.Increment(ref Q); // ChildClass<int> will have a different "Q" than ChildClass<double> 
    Interlocked.Increment(ref P); // all types of ChildClass will increment the same P
}

或原lock

public class BaseClass
{
    protected static int P = 0;
    protected static object pLock = new object();
}
public class ChildClass<T> : BaseClass
{
    private static int Q = 0;
    private static object qLock = new object();
    public void Inc()
    {
        lock(qLock)
        {
            qLock++;
        }
        lock(pLock)
        {
            qLock++;
        }
    }
}

注意,对于每个T,将有一个不同的ChildClass<T>.Q,但只能有一个BaseClass.P。这意味着您必须使用单独的锁对象来处理QP(技术上用于锁定P的任何东西也可以用于锁定所有Q,但这可能不是您想要做的)。

您的模式是有效的,没有问题。没有静态继承这样的东西,但是您可以像通常那样访问任何类型的静态成员(只要它们对派生类可见,例如不是private):

BaseClass.P = 10;
ChildClass<string>.Q = 20;

c#规范指出,对32位整数(即int)的单次读写是原子性的,这意味着它们可以在单个指令中完成,并且不会在另一个线程中看到写入一半的变量。

12.5变量引用原子性

下列数据类型的读写必须是原子类型:bool、char、byte、sbyte、short、ushort、uint、int、float和引用类型。此外,具有前面列表中基础类型的枚举类型的读写也必须是原子的。其他类型(包括long、ulong、double和decimal)以及用户定义类型的读写不需要是原子类型。

当然,读和写不能保证是原子的。例如,增加变量的值需要先读后写,这就是Interlocked方法发挥作用的地方。

顺便说一下,您可能意识到您将只获得一个P静态变量,但是Q静态变量的数量与您的类型ChildClass<T>的不同通用实例一样多。