简体   繁体   English

泛型类中静态字段的合适解决方法?

[英]Suitable workaround for static field in generic class?

Given that generic types create separate instances of static fields per-type combination, is this a valid pattern to use if I want to have a static field across all types? 鉴于泛型类型为每种类型的组合创建了单独的静态字段实例,如果我希望所有类型都具有静态字段,这是否是有效的模式?

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

Is there anything unsafe about this approach? 这种方法有什么不安全的地方吗? My toy example works, but I just wanted to make sure there are no horrible side effects, threading consequences, etc :) 我的玩具示例可行,但我只是想确保没有可怕的副作用,线程后果等:)

You can use Interlocked.Increment for more thread-safe code. 您可以使用Interlocked.Increment获得更多线程安全代码。

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
}

or plain old lock 或普通的旧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++;
        }
    }
}

Note that for every T there will be a different ChildClass<T>.Q , but there shall only ever be one BaseClass.P . 注意,对于每个T ,将有一个不同的ChildClass<T>.Q ,但将永远只有一个BaseClass.P That means you'd have to use separate lock objects for dealing with Q and P (technically anything you use to lock P can also be used to lock all Q 's but that's probably not what you want to do). 这意味着您必须使用单独的锁定对象来处理QP (从技术上讲,您用来锁定P所有内容也可以用于锁定所有Q ,但这可能不是您想要的)。

Your pattern is valid and has no issues. 您的模式有效,没有问题。 There is no such thing as static inheritance , but you can access the static members of any type just like you normally would (provided they are visible to your derived class, eg not private ): 没有诸如静态继承之类的东西,但是您可以像平常一样访问任何类型的静态成员(前提是它们对您的派生类可见,例如,不是private ):

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

The C# specification states that single reads or writes to 32-bit integers (ie int ) are atomic , which means they can complete within a single instruction and never will a half-written variable be visible to another thread. C#规范指出,单个读取或写入32位整数(即int )是原子的 ,这意味着它们可以在一条指令中完成,并且半写入变量永远不会对另一个线程可见。

12.5 Atomicity of variable references 12.5变量引用的原子性

Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. 下列数据类型的读取和写入应为原子类型:bool,char,byte,sbyte,short,ushort,uint,int,float和引用类型。 In addition, reads and writes of enum types with an underlying type in the previous list shall also be atomic. 另外,对上一个列表中具有基础类型的枚举类型的读写也应该是原子的。 Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, need not be atomic. 其他类型的读取和写入(包括long,ulong,double和decimal)以及用户定义的类型都不需要是原子的。

Of course, reading and writing is not guaranteed to be atomic. 当然,阅读写作是不能保证是原子。 For example, incrementing a variable's value requires it to be read then written, and that's where the Interlocked methods come into play. 例如,增加变量的值要求先读取然后再写入,这就是Interlocked方法起作用的地方。

By the way, you are probably aware that you'll get only one P static variable, but as many Q static variables as there are different generic instances of your type ChildClass<T> . 顺便说一句,您可能知道只有一个P静态变量,但与类型为ChildClass<T>不同通用实例一样多的Q静态变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM