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

本文关键字:ref 转换 int 类型 枚举 | 更新日期: 2023-09-27 17:55:51

我想将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仅适用于引用类型和选择值类型(请参阅此处)。由于MyEnum实际上是皮肤下的 int,我想我应该能够将其作为 ref int 传递:

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

但是,这似乎也不起作用。我收到以下错误:

错误 CS1503:参数 1:无法从"ref MyEnum"转换为"ref int"

在传递之前进行铸造,例如 ref (int)s_field,也无济于事。

我该如何解决这个问题?有没有办法将CompareExchange与枚举一起使用,或者我必须改用整数?

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

你想使用联合吗?

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类来实现这一点。运行以下命令以将包含该类的包安装到您的应用中:

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 或更高版本。