System.MissingMethodException:Int32 System.Environment.get_CurrentManagedThreadId()

35

以下异常可能是由什么引起的?

System.MissingMethodException Int32 System.Environment.get_CurrentManagedThreadId()

这个方法调用似乎是由C#编译器为生成返回类型为IEnumerable<>的方法而生成的。

.NET Framework v4.0 x86已安装,二进制文件编译为v4.0 Any CPU。


1
这也会弹出"找不到方法:Int32.System.Environment.get_CurrentManagedThreadId()"。 - EBarr
3个回答

51

CurrentManagedThreadId 是 .NET 4.5 的一个属性,所以你需要安装 4.5 才能运行代码。 有关此问题可能出现的分析,请参见迭代器块,缺少方法和.NET 4.5

简而言之:

如果你在安装了 .NET 4.5 的系统上构建面向 .NET 4.0 的应用程序,它将使用 4.5 作为编译的基础,因为 .NET 4.0 Framework 总是被 .NET 4.5 覆盖。

如果你的应用程序还使用了 yield return,它将在仅安装了 4.0 的系统上失败,因为编译此语句的实现使用了一个新属性,只有当编译为 4.5 Framework 时才可用。

要解决这个问题,请确保编译器系统具有 4.0 引用程序集。


最近我一直在研究这个问题,注意到一个安装了4.6.1的构建服务器再次创建依赖于 Thread.CurrentThread.ManagedThreadId 的代码。我无法在网上找到相关文档记录,但这表明微软已经在后续版本中修复了这个问题。 - Iain

3

支持 floele 的回答;为了更好的理解,这里简要分析一下问题:

当编译器处理返回一个 IEnumerable 的迭代器块时,它会生成一个私有的 IEnumerable 类来保存迭代逻辑。以下是 4.0 编译器为其 GetEnumerator 方法生成的 IL 的开头:

.method private final hidebysig newslot virtual 
    instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' () cil managed 
{
    .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = (
        01 00 00 00
    )
    .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
    // Method begins at RVA 0x57848
    // Code size 89 (0x59)
    .maxstack 6
    .locals init (
        [0] bool,
        [1] class DOT.Core.MiscHelpers/'<ReadLines>d__0',
        [2] class [mscorlib]System.Collections.Generic.IEnumerator`1<string>
    )

    IL_0000: call class [mscorlib]System.Threading.Thread [mscorlib]System.Threading.Thread::get_CurrentThread()
    IL_0005: callvirt instance int32 [mscorlib]System.Threading.Thread::get_ManagedThreadId()
    IL_000a: ldarg.0
    IL_000b: ldfld int32 DOT.Core.MiscHelpers/'<ReadLines>d__0'::'<>l__initialThreadId'
    IL_0010: bne.un IL_0027

请注意对 System.Threading.Thread::get_CurrentThread()System.Threading.Thread::get_ManagedThreadId(); 的调用。生成的方法使用这些来执行一个优化,即如果立即使用了 IEnumerable [1],则返回相同的对象实例(节省构造函数调用的成本)。
以下是由4.5编译器生成的IL代码:
.method private final hidebysig newslot virtual 
    instance class [mscorlib]System.Collections.Generic.IEnumerator`1<string> 'System.Collections.Generic.IEnumerable<System.String>.GetEnumerator' () cil managed 
{
    .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = (
        01 00 00 00
    )
    .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<string>::GetEnumerator()
    // Method begins at RVA 0x4830c
    // Code size 64 (0x40)
    .maxstack 2
    .locals init (
        [0] class DOT.Core.MiscHelpers/'<ReadLines>d__0'
    )

    IL_0000: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId()
    IL_0005: ldarg.0
    IL_0006: ldfld int32 DOT.Core.MiscHelpers/'<ReadLines>d__0'::'<>l__initialThreadId'
    IL_000b: bne.un IL_002b

请注意,先前方法中的两个调用现已被System.Environment::get_CurrentManagedThreadId()替换,这是在.NET 4.5中添加的属性。
由于4.5升级覆盖了4.0 C#编译器(csc.exe),在您的计算机上为4.0编译的代码将使用新的IL模板,并且不会在普通的4.0安装上运行,除非您拥有.NET 4.0参考程序集[2],这将导致编译器生成旧版本的IL。
[1]也就是说,在创建它的线程上第一次使用它(例如在foreach语句中)。
[2]实际上可以从.NET Framework安装程序中提取.NET 4.0编译器,并修改项目文件以使用该编译器编译代码。 这可能是解决问题的另一种方法,但这是一个长故事,我不会在此详细说明。

0

请检查您的NuGet包,确保所有项目都使用相同版本的DLL。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接