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

时间:2012-03-02 13:08:53

标签: c# .net .net-4.0 enums 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;
}

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

result = default(TEnum);   /// (*)

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

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

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

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

public static SomeEnum MyField;
....
Enum.TryParse("Value", out MyField);

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

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

4 个答案:

答案 0 :(得分:7)

与每个其他局部变量和参数一样,

result是每次调用。 by-ref参数的线程安全性是 little 更复杂的描述,但是:在每个合理的用法中 - 这不会是一个问题。我可以强制它有风险的场景(由于by-ref传递),但这将是一个人为的例子。

典型用法:

SomeEnumType foo;
if(Enum.TryParse(s, true, out foo)) {...}

非常安全。

以下内容有点复杂:

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

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

答案 1 :(得分:5)

是的 - 是的。

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

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

如果result是一个类级变量,那么这就是一个问题,但这很好。

答案 2 :(得分: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");
            }
        }
    }
}

它迟早(可能更早)抛出“Not threadsafe”异常。

答案 3 :(得分:2)

这不是TryParse是否是线程安全的问题,而是使用它的代码(您的代码)是否是线程安全的。如果您传入结果变量,然后让另一个线程访问它而没有一些互斥保护,那么您可能会遇到问题,但问题出在您的代码中。