简体   繁体   English

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

[英]How to apply InterLocked.Exchange for Enum Types in C#?

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

could be solved with: 可以解决:

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

Is there any better way for this problem? 有没有更好的方法来解决这个问题?

Is there any better way for this problem? 有没有更好的方法来解决这个问题?

If you need to use Interlocked.Exchange then this is the best way, in fact I think it is the only way to Exchange an enum. 如果你需要使用Interlocked.Exchange那么这是最好的方法,事实上我认为这是交换枚举的唯一方法。

The reason you get the compiler error is that the compiler thinks you want to use Exchange<T> , but T needs to be a reference type for this to work, since you are not using a reference type it fails. 您收到编译器错误的原因是编译器认为您要使用Exchange<T> ,但是T需要是一个引用类型,因为您没有使用它失败的引用类型。 So, the best work around is to cast to an int as you have done, and thus force the compiler to use the non-generic Exchange(int, int) . 因此,最好的解决方法是像你一样强制转换为int ,从而强制编译器使用非泛型的Exchange(int, int)

You appear to not need the "exchange" feature of Interlocked.Exchange, as you are ignoring its return value. 您似乎不需要Interlocked.Exchange的“交换”功能,因为您忽略了它的返回值。 Therefore I think the solution that might make you happiest is to mark _field as volatile: 因此,我认为可能让您最开心的解决方案是将_field标记为volatile:

private volatile MyEnum _field;

The Interlocked methods are fine. Interlocked方法很好。 You could use a plain old lock , but that seems like overkill here. 你可以使用一个普通的旧lock ,但这似乎有点矫枉过正。 However, you are going to need to use a guarded read of some kind in the getter otherwise you may run into memory barrier issues. 但是,您需要在getter中使用某种保护读取,否则可能会遇到内存障碍问题。 Since you are already using an Interlocked method in the setter it makes sense to do the same in the 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); }
}  

You could also get away with marking the field as volatile if you like. 如果你愿意,你也可以将该字段标记为volatile

Is there any better way for this problem? 有没有更好的方法来解决这个问题?

I use a class instead of Enum: 我使用的是一个类而不是枚举:

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

Why not simply synchonrize the threading? 为什么不简单地同步线程?

protected static object _lockObj = new object();

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

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

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