如何在C#中为Enum类型应用InterLocked.Exchange?

public enum MyEnum{Value1, Value2} class MyClass { private MyEnum _field; public MyEnum Field // added for convenience { get { return _field; } set { Interlocked.Exchange(ref _field, value); // ERROR CS0452 } } } 

可以解决:

  public enum MyEnum{Value1, Value2} public class MyClass2 { private int _field; //change to int public MyEnum Field // added for convenience { get { return (MyEnum)_field; } set { System.Threading.Interlocked.Exchange(ref _field, (int)value); } } } 

有没有更好的方法来解决这个问题?

有没有更好的方法来解决这个问题?

如果你需要使用Interlocked.Exchange那么这是最好的方法,事实上我认为这是交换枚举的唯一方法。

您收到编译器错误的原因是编译器认为您要使用Exchange ,但是T需要是一个引用类型,因为您没有使用它失败的引用类型。 因此,最好的解决方法是像你一样强制转换为int ,从而强制编译器使用非generics的Exchange(int, int)

您似乎不需要Interlocked.Exchange的“交换”function,因为您忽略了它的返回值。 因此,我认为可能让您最开心的解决方案是将_field标记为volatile:

 private volatile MyEnum _field; 

Interlocked方法很好。 你可以使用一个普通的旧lock ,但这似乎有点矫枉过正。 但是,您需要在getter中使用某种保护读取,否则可能会遇到内存障碍问题。 由于您已经在setter中使用了Interlocked方法,因此在getter中执行相同操作是有意义的。

 public MyEnum Field // added for convenience { get { return (MyEnum)Interlocked.CompareExchange(ref _field, 0, 0); } set { Interlocked.Exchange(ref _field, (int)value); } } 

如果你愿意,你也可以将该字段标记为volatile

为什么不简单地同步线程?

 protected static object _lockObj = new object(); set { lock(_lockObj) { _field = value; } } 

有没有更好的方法来解决这个问题?

我使用一个类而不是枚举:

 public class DataCollectionManagerState { public static readonly DataCollectionManagerState Off = new DataCollectionManagerState() { }; public static readonly DataCollectionManagerState Starting = new DataCollectionManagerState() { }; public static readonly DataCollectionManagerState On = new DataCollectionManagerState() { }; private DataCollectionManagerState() { } public override string ToString() { if (this == Off) return "Off"; if (this == Starting) return "Starting"; if (this == On) return "On"; throw new Exception(); } } public class DataCollectionManager { private static DataCollectionManagerState _state = DataCollectionManagerState.Off; public static void StartDataCollectionManager() { var originalValue = Interlocked.CompareExchange(ref _state, DataCollectionManagerState.Starting, DataCollectionManagerState.Off); if (originalValue != DataCollectionManagerState.Off) { throw new InvalidOperationException(string.Format("StartDataCollectionManager can be called when it's state is Off only. Current state is \"{0}\".", originalValue.ToString())); } // Start Data Collection Manager ... originalValue = Interlocked.CompareExchange(ref _state, DataCollectionManagerState.On, DataCollectionManagerState.Starting); if (originalValue != DataCollectionManagerState.Starting) { // Your code is really messy throw new Exception(string.Format("Unexpected error occurred. Current state is \"{0}\".", originalValue.ToString())); } } }