Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
435 views
in Technique[技术] by (71.8m points)

c# - 与枚举互锁。比较交换(Interlocked.CompareExchange with enum)

I'm trying to use Interlocked.CompareExchange with this enum:

(我正在尝试与此枚举一起使用Interlocked.CompareExchange :)

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

The following code doesn't compile, but that's what I want do do:

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

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

Sure I can use a int instead of the enum and use a property:

(当然,我可以使用int代替枚举并使用属性:)

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

Then cast the enums to a int:

(然后将枚举转换为int:)

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

But are there better ways to do this?

(但是,有更好的方法吗?)

  ask by joe translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's possible from IL, and it's possible to create a helper method for this that can be used from C#.

(可以从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);
    }
}

Output:

(输出:)

x: Y
y: X

This just forwards the arguments to the correct Interlocked.Exchange overload.

(这只是将参数转发到正确的Interlocked.Exchange重载。)

It fails badly if T isn't really an enum type, or its underlying type doesn't have an Interlocked.Exchange overload.

(如果T不是真正的枚举类型,或者它的基础类型没有Interlocked.Exchange重载,则它将严重失败。)

The generated IL is verifiable, at least according to PEVerify, as can be checked by making this use AssemblyBuilder and saving the result to a file.

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...