如何将 ref [枚举类型] 转换为 ref int?

How to convert a ref [enum type] to a ref int?

我想将 Interlocked.CompareExchange 与继承自 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 仅适用于引用类型和 select 值类型(参见 here)。由于 MyEnum 实际上是皮肤下的一个整数,我想我应该能够将它作为一个 ref int 传递:

// 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 与枚举一起使用,还是我必须改用整数?

您想使用联合吗?

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

当然,有点繁琐...

评估后转换值呢?

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

也许你可以使用:

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

我相信现在可以使用 .NET Core 中引入的 Unsafe class。 运行 将包含 class 的软件包安装到您的应用中:

Install-Package System.Runtime.CompilerServices.Unsafe

那你就可以Interlocked.CE(ref Unsafe.As<MyEnum, int>(ref s_field), (int)MyEnum.B, (int)MyEnum.A)了。请注意,这需要对 ref returns 的 C# 7 语言支持,因此您需要拥有 VS2017 或更高版本。