Enum.TryParse - 它是线程安全的吗?

abi*_*ski 5 .net c# enums .net-4.0 tryparse

我试图弄清楚.NET 4.0的Enum.TryParse是否是线程安全的.

源代码(反编译)是:

[SecuritySafeCritical]
public static bool TryParse<TEnum>(string value, bool ignoreCase, out TEnum result) where TEnum : struct
{
    result = default(TEnum);   /// (*)
    Enum.EnumResult enumResult = default(Enum.EnumResult);
    enumResult.Init(false);
    bool result2;
    if (result2 = Enum.TryParseEnum(typeof(TEnum), value, ignoreCase, ref enumResult))
    {
        result = (TEnum)enumResult.parsedEnum;
    }
    return result2;
}
Run Code Online (Sandbox Code Playgroud)

对我来说似乎有问题的是这一行:

result = default(TEnum);   /// (*)
Run Code Online (Sandbox Code Playgroud)

如果另一个线程在将其设置为默认值之后,并且在将其设置为已解析值之前访问结果,该怎么办?

[编辑]按照Zoidberg的回答,我想稍微改一下这个问题.

问题是,我想,如果Enum.TryParse是"事务性的"(或原子的).

假设我有一个静态字段,并将其传递给Enum.TryParse:

public static SomeEnum MyField;
....
Enum.TryParse("Value", out MyField);
Run Code Online (Sandbox Code Playgroud)

现在,当执行TryParse时,另一个线程访问MyField.TryParse会将MyField的值更改为SomeEnum的默认值一段时间,然后才会将其设置为已解析的值.

这不一定是我的代码中的错误.我希望Enum.TryParse能够将MyField设置为已解析的值,或者根本不触摸它,而不是将其用作临时字段.

Mar*_*ell 7

result与每个其他局部变量和参数一样,是每次调用.by-ref参数的线程安全性要稍微复杂一些,但是:在每个合理的用法中 - 这都不是问题.我可以强制它有风险的场景(由于by-ref传递),但这将是一个人为的例子.

典型用法:

SomeEnumType foo;
if(Enum.TryParse(s, true, out foo)) {...}
Run Code Online (Sandbox Code Playgroud)

非常安全.

以下有点复杂:

var objWithField = new SomeType();
// thread 1:
{
    Enum.TryParse(x, true, out objWithField.SomeField));
}
// thread 2:
{
    Enum.TryParse(y, true, out objWithField.SomeField));
}
Run Code Online (Sandbox Code Playgroud)

并且不是线程安全的,但是比你在问题中描述的那些更微妙的原因.


Rob*_*ine 5

是的.

在您反编译的方法中根本没有共享状态.

如果另一个线程调用相同的方法,它将获得所有本地的自己的副本,result并由调用者传入.

如果result曾经是一个类级变量,那么这将是一个问题,但这很好.

  • 警告; `result`是by-ref,所以虽然指针的本地副本确实是孤立的,但是底层值是by-ref并且存在风险,但仅限于非常人为的例子. (3认同)

And*_*ker 3

结果(以及它引用的变量)可以成为默认值(T),尽管字符串值包含不同的枚举值(如果这就是您的意思)。

尝试以下程序:

public enum FooBar
{
    Foo = 0,
    Bar
}

internal class Program
{
    private static FooBar fb = FooBar.Bar;

    private static void Main()
    {
        new Thread(() =>
                       {
                           while (true)
                           {
                               if (Program.fb == FooBar.Foo) // or try default(FooBar), which is the same
                               {
                                   throw new Exception("Not threadsafe");
                               }
                           }
                       }).Start();

        while (true)
        {
            if (!Enum.TryParse("Bar", true, out fb) || fb == FooBar.Foo)
            {
                throw new Exception("Parse error");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它迟早(可能更快)会抛出“非线程安全”异常。