C# 如何使T型字段变为易失性字段?

C# 如何使T型字段变为易失性字段?,c#,generics,C#,Generics,我试图将一堆重复代码整合到具有以下结构的实用程序类中: public class Shared<T> { private volatile T _value; public object Lock { get; private set; } public T Value { get { lock (Lock) return _value; } set { lock (Lock) _value = value; }

我试图将一堆重复代码整合到具有以下结构的实用程序类中:

public class Shared<T>
{
    private volatile T _value;

    public object Lock { get; private set; }

    public T Value
    {
        get { lock (Lock) return _value; }
        set { lock (Lock) _value = value; }
    }

    public Shared(T startingValue)
    {
        _value = startingValue;
        Lock = new object();
    }

    public Shared()
        : this(default(T))
    {
    }
}
公共类共享
{
私有挥发性T_值;
公共对象锁{get;private set;}
公共价值
{
获取{lock(lock)返回_值;}
设置{lock(lock)_value=value;}
}
公共共享(T起始值)
{
_值=起始值;
Lock=新对象();
}
公共共享()
:此(默认值(T))
{
}
}
然而,C#不会让我这么做。文档表明
T
必须是引用类型或原语之一(int、bool等)。我只关心引用类型和bool。显然,我不能使用无界类型
T
。有没有办法让这一切顺利进行?甚至可以向其添加约束以使其作为共享的
工作吗?我甚至不允许将其他结构类型标记为volatile.:(


如果没有可能的方法将其标记为volatile,我是否有其他保证,当多个线程尝试读取此值时,它不会被优化掉?

您可以轻松地将泛型类型限制为仅引用

public class Shared<T> where T : class
公共类共享,其中T:class
…但是也无法将其限制为bool。该类非常小,因此您可以为布尔类型创建特定的实现

但是…


读取和写入值期间的锁定完全无效。对象引用的读取/写入在.NET中是原子的,因此不需要锁定。它只会降低锁定速度。(布尔值实现为4字节整数,它们也是原子的,因此布尔值版本也不需要)

volatile关键字意味着每次读取该值时,它都将确保再次从内存中读取该值。这解决了该值可能缓存在寄存器或一级/二级缓存中的问题。在这种情况下,后续访问将是寄存器/缓存值,即使另一个CPU可能已在主内存中对其进行了更改。因此您的volatile将阻止将值缓存在寄存器中,并确保每次读取都与主内存一致。

(这不是特定于
volatile
问题,而是此类情况下可能的一般解决方法。)

你可以让你的类实现一个接口(比如,
IShared
)。通过一个通用工厂方法构造它的实例。然后你可以提供多个实现


对于引用类型,可以返回已有类的实例,约束条件为
T:class
。对于基元类型,可以返回实现
IShared
IShared
等的专用非泛型类的实例。

可以添加
其中T:class
,使其与引用一起工作pes,但是没有办法使它同时适用于引用类型和
bool
。您需要另一个非泛型类用于
bool
,例如
SharedBool
您真的需要“volatile”吗如果您使用lock@danisius我不知道。是吗?你有没有试过在T:class
@Med.Amine.Touil中共享
公共类?是的。这很有效,但会剥夺我创建
共享
对象的能力。如果我删除
volatile
,我可以继续使用
共享
,这会让我非常高兴。per,volatile是一个插件对编译器的说明。它在运行时不做任何操作。它只是防止编译器将其转换为硬值,因为它认为您不会在任何地方更改它。感谢链接。正如链接所说,“这确保字段中始终存在最新的值”。我的观点是,这与hardware管理缓存。CPU从不更改主存中的值。它必须始终将该值拉入CPU缓存以进行更改。CPU缓存始终包含真相;如果该值已在CPU缓存中,则不会使用主存。Volatile只是告诉编译器不要优化该值。“在读取和写入值的过程中,您的锁定是完全无用的。"--我知道这些类型的原子性质,但这并不意味着我的锁没有用处。我公开了锁。关键是其他代码可以锁定对象,从而防止在持有锁的整个时间内更改或查看值。这个答案与我试图实现的更好。而无论如何,我可能最终不需要
volatile
,这确实可以解决这个问题。拥有工厂方法(并隐藏构造函数)将允许我创建子类来处理C#的阻力。