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

时间:2011-08-24 14:28:57

标签: c# .net multithreading

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

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

5 个答案:

答案 0 :(得分:7)

  

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

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

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

答案 1 :(得分:5)

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

private volatile MyEnum _field;

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

protected static object _lockObj = new object();

set
{
    lock(_lockObj)
    {
         _field = value;
    }
}

答案 4 :(得分:0)

  

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

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

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