System.MissingMethodException Int32 System.Environment。 get_CurrentManagedThreadId()
什么可能导致以下exception?
System.MissingMethodException Int32 System.Environment.get_CurrentManagedThreadId()
这种方法调用似乎是由C#编译器为产生IEnumerable<>
方法生成的。
安装.NET Framework v4.0 x86,并为v4.0 Any CPU编译二进制文件。
CurrentManagedThreadId
是一个.NET 4.5属性,所以你需要4.5来运行代码。 请参阅迭代器块,缺less的方法和.NET 4.5 ,以分析如何解决此问题。
简而言之:
如果在安装了.NET 4.5的系统上构build应用程序(以.NET 4.0为目标),则它将使用4.5作为编译的基础,因为.NET 4.0框架总是被.NET 4.5覆盖。
如果您的应用程序也使用yield return
,那么只有安装了4.0的系统才会失败,因为此语句的实现在为4.5 Framework编译时使用了新属性。
要解决它,请确保您的编译器系统具有4.0引用程序集。
借调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();
的调用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模板,并且不会在vanilla 4.0安装上运行,除非您有.NET 4.0 Reference Assemblies [2] ,这将导致编译器生成旧版本的IL。
[1]也就是第一次在创build它的线程上使用它(例如在一个foreach语句中)。
[2]实际上可以从.NET Framework安装程序中提取.NET 4.0编译器,并修改项目文件以编译代码。 这可能是解决问题的另一种方法,但这是一个漫长的故事,我不会在这里详细讨论