Подтвердить что ты не робот

Как применять InterLocked.Exchange для типов Enum в С#?

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

Есть ли лучший способ для этой проблемы?

4b9b3361

Ответ 1

Есть ли лучший способ для этой проблемы?

Если вам нужно использовать Interlocked.Exchange, тогда это лучший способ, на самом деле я думаю, что это единственный способ обмена перечислением.

Причина, по которой вы получаете ошибку компилятора, заключается в том, что компилятор считает, что вы хотите использовать Exchange<T>, но T должен быть ссылочным типом для этого, поскольку вы не используете ссылочный тип, который он терпит неудачу. Таким образом, лучшая работа заключается в том, чтобы выполнить int, как вы это сделали, и, таким образом, заставить компилятор использовать не-общий Exchange(int, int).

Ответ 2

Кажется, вам не нужна функция "exchange" Interlocked.Exchange, поскольку вы игнорируете ее возвращаемое значение. Поэтому я думаю, что решение, которое может сделать вас счастливее, - отметить значение _field как изменчивое:

private volatile MyEnum _field;

Ответ 3

Способы Interlocked прекрасны. Вы можете использовать простой старый lock, но это кажется излишним. Тем не менее, вам понадобится использовать защищенное чтение какого-либо типа в геттере, иначе вы можете столкнуться с проблемами защиты памяти. Поскольку вы уже используете метод 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, если хотите.

Ответ 4

Почему бы просто не синхронизировать потоки?

protected static object _lockObj = new object();

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

Ответ 5

Есть ли лучший способ для этой проблемы?

Я использую класс вместо 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 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()));
        }
    }
}