2016-07-06 4 views
0

Я хочу использовать Interlocked.CompareExchange с перечислимого типа, который наследует от междунар, например, так:Как преобразовать ref [enum type] в ref int?

public enum MyEnum : int { A, B } 

public class MyClass 
{ 
    private static readonly MyEnum s_field = MyEnum.A; 

    public void Foo() 
    { 
     if (Interlocked.CompareExchange(ref s_field, MyEnum.B, MyEnum.A) == MyEnum.A) 
     { 
      Console.WriteLine("Changed from A to B"); 
     } 
    } 
} 

Однако CompareExchange работает только со ссылочными типами и типами выберите значение (см here). Поскольку MyEnum действительно является ИНТ под кожей, я думал, что я должен быть в состоянии передать его как исх междунар:

// should call CompareExchange(ref int, int, int) overload 
Interlocked.CompareExchange(ref s_field, (int)MyEnum.B, (int)MyEnum.A); 

Однако, это, кажется, не работает. Я получаю следующую ошибку:

Error CS1503: Argument 1: cannot convert from 'ref MyEnum' to 'ref int'

Кастинг перед его передачей, например. ref (int)s_field, не помогает.

Как это исправить? Есть ли способ использовать CompareExchange с перечислениями, или я должен использовать ints вместо этого?

+0

Есть ли какая-то конкретная причина, по которой вы работаете с перечислениями? «Блокировка» ограничена номерами в этом, что угадывает ... Можете ли вы работать с константами (я знаю, ... запах дизайна, хотя)? –

+0

@AndreasNiedermair Да, я просто думаю, что код выглядит лучше с перечислениями. –

+0

Вы не можете делать то, что хотите, поскольку 'Interlocked' не предоставляет вариант API-интерфейса enum. Вы должны использовать 'int'. – GreatAndPowerfulOz

ответ

0

Я считаю, что теперь это возможно с классом Unsafe, который был представлен в .NET Core. Выполнить это установить пакет, содержащий класс в приложение:

Install-Package System.Runtime.CompilerServices.Unsafe 

Затем вы можете сделать Interlocked.CE(ref Unsafe.As<MyEnum, int>(ref s_field), (int)MyEnum.B, (int)MyEnum.A). Обратите внимание, что для этого требуется поддержка языка C# 7 для возврата ref, поэтому вам нужно иметь VS2017 или новее.

0

Вы хотите использовать союз?

public enum MyEnum : int { A, B } 

[StructLayout(LayoutKind.Explicit)] 
struct IntEnumUnion 
{ 
    [FieldOffset(0)] 
    public MyEnum Enum; 
    [FieldOffset(0)] 
    public int Int; 
} 

private static IntEnumUnion s_field; 
s_field.Enum = MyEnum.A; 

if (Interlocked.CompareExchange(ref s_field.Int, (int)MyEnum.B, (int)MyEnum.A) 
    == (int)MyEnum.A) 
{ 
    Console.WriteLine("Changed from A to B"); 
} 

Конечно, это немного громоздко ...

0

Что о преобразовании значения после оценки?

 int value = (int)MyEnum.A; 

     var result = Interlocked.CompareExchange(ref value, (int)MyEnum.A, (int)MyEnum.B); 

     if((MyEnum)result == MyEnum.A) 
      System.Console.WriteLine("Changed from A to B"); 
0

Может быть, вы можете просто использовать:

static readonly object lockInstance = new object(); 

public static TSimple CompareExchange<TSimple>(ref TSimple location1, TSimple value, TSimple comparand) 
{ 
    lock (lockInstance) 
    { 
    var location1Read = location1; 
    if (EqualityComparer<TSimple>.Default.Equals(location1Read, comparand)) 
    { 
     // location1 write 
     location1 = value; 
    } 
    return location1Read; 
    } 
} 

Внимание: lock вещь только предотвращает изменения location1 происходящие через этот конкретный метод. Он не может помешать другим потокам манипулировать location1 другими способами, пока мой метод работает. Если это проблема, возможно, используйте int и получите public static class MyEnum { public const int A = 0; public const int B = 1; }.

 Смежные вопросы

  • Нет связанных вопросов^_^