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设置为已解析的值,或者根本不触摸它,而不是将其用作临时字段.
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)
并且不是线程安全的,但是比你在问题中描述的那些更微妙的原因.
是的.
在您反编译的方法中根本没有共享状态.
如果另一个线程调用相同的方法,它将获得所有本地的自己的副本,result
并由调用者传入.
如果result
曾经是一个类级变量,那么这将是一个问题,但这很好.
结果(以及它引用的变量)可以成为默认值(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)
它迟早(可能更快)会抛出“非线程安全”异常。
归档时间: |
|
查看次数: |
834 次 |
最近记录: |