gpt4 book ai didi

c# - Interlocked.CompareExchange 与枚举

转载 作者:IT王子 更新时间:2023-10-29 04:53:13 33 4
gpt4 key购买 nike

我正在尝试使用 Interlocked.CompareExchange使用此枚举:

public enum State {
Idle,
Running,
//...
}

以下代码无法编译,但这是我想要做的:

if (Interlocked.CompareExchange(ref state, State.Running, State.Idle) != State.Idle) {
throw new InvalidOperationException("Unable to run - not idle");
}

当然我可以使用 int 而不是 enum 并使用属性:

private int state = (int)State.Idle;
public State { get { return (State)state; } }

然后将枚举转换为 int:

if (Interlocked.CompareExchange(ref state, (int)State.Running, (int)State.Idle) !=  (int)State.Idle) {
throw new InvalidOperationException("Unable to run - not idle");
}

但是有更好的方法吗?

最佳答案

这在 IL 中是可能的,并且可以为此创建一个可在 C# 中使用的辅助方法。

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

static class CompareExchangeEnumImpl<T>
{
public delegate T dImpl(ref T location, T value, T comparand);
public static readonly dImpl Impl = CreateCompareExchangeImpl();

static dImpl CreateCompareExchangeImpl()
{
var underlyingType = Enum.GetUnderlyingType(typeof(T));
var dynamicMethod = new DynamicMethod(string.Empty, typeof(T), new[] { typeof(T).MakeByRefType(), typeof(T), typeof(T) });
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.Emit(OpCodes.Ldarg_2);
ilGenerator.Emit(
OpCodes.Call,
typeof(Interlocked).GetMethod(
"CompareExchange",
BindingFlags.Static | BindingFlags.Public,
null,
new[] { underlyingType.MakeByRefType(), underlyingType, underlyingType },
null));
ilGenerator.Emit(OpCodes.Ret);
return (dImpl)dynamicMethod.CreateDelegate(typeof(dImpl));
}
}

public static class InterlockedEx
{
public static T CompareExchangeEnum<T>(ref T location, T value, T comparand)
{
return CompareExchangeEnumImpl<T>.Impl(ref location, value, comparand);
}
}

public enum Foo
{
X,
Y,
}

static class Program
{
static void Main()
{
Foo x = Foo.X;
Foo y = Foo.Y;
y = InterlockedEx.CompareExchangeEnum(ref x, y, Foo.X);
Console.WriteLine("x: " + x);
Console.WriteLine("y: " + y);
}
}

输出:

x: Yy: X

这只是将参数转发给正确的 Interlocked.Exchange 重载。如果 T 不是真正的枚举类型,或者它的底层类型没有 Interlocked.Exchange 重载,它就会严重失败。

生成的 IL 是可验证的,至少根据 PEVerify,可以通过使用 AssemblyBuilder 并将结果保存到文件来进行检查。

关于c# - Interlocked.CompareExchange 与枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18358518/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com