2013-03-22 9 views
35

Was könnte die folgende Ausnahme verursachen?System.MissingMethodException Int32 System.Umgebung. get_CurrentManagedThreadId()

System.MissingMethodException Int32 System.Environment.get_CurrentManagedThreadId() 

Dieser Methodenaufruf scheint von C# Compiler für Methoden generiert werden IEnumerable<> ergibt.

.NET Framework v4.0 x86 ist installiert und die Binärdatei ist für v4.0 Any CPU kompiliert.

+1

Dies erscheint auch als "Methode nicht gefunden:' Int32.System.Environment.get_CurrentManagedThreadId() '. – EBarr

Antwort

52

CurrentManagedThreadId ist eine .NET 4.5-Eigenschaft, daher benötigen Sie 4,5, um den Code auszuführen. Siehe Iterator blocks, missing methods, and .NET 4.5 für eine Analyse, wie dieses Problem auftreten könnte.

Kurz:

Wenn Sie Ihre Anwendung erstellen (gezielte bei .NET 4.0) auf einem System mit .NET 4.5 installiert ist, wird es 4,5 als Grundlage für die Erstellung zu verwenden, da die .NET Framework 4.0 wird immer von .NET 4.5 überschrieben.

Wenn Ihre Anwendung dann auch yield return verwendet, wird es auf Systemen fehlschlagen, die nur 4.0 installiert haben, da die Implementierung dieser Anweisung beim Kompilieren für das Framework 4.5 eine neue Eigenschaft verwendet.

Um es zu lösen, stellen Sie sicher, dass Ihr Compiler-System die 4.0 Referenz-Baugruppen hat.

+0

Ich habe dieses Problem kürzlich untersucht und festgestellt, dass ein Build-Server mit 4.6.1 Code wieder installiert hat, der von 'Thread.CurrentThread.ManagedThreadId' abhing. Ich konnte das nirgendwo online finden, aber das deutet darauf hin, dass MS dieses Problem in späteren Versionen behoben hat. – Iain

3

Absenden floele 's Antwort; Für mehr Kontext, hier eine kurze Analyse des Problems:

Wenn der Compiler einen Iterator-Block verarbeitet, der eine IEnumerable zurückgibt, generiert er eine private IEnumerable Klasse, die die Iterationslogik enthält. Dies ist der Beginn des IL erzeugt für seine GetEnumerator Verfahren durch den 4.0-Compiler:

.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 

Beachten Sie die Anrufe zu System.Threading.Thread::get_CurrentThread() und System.Threading.Thread::get_ManagedThreadId();. Die generierte Methode verwendet dies, um eine Optimierung durchzuführen, bei der, wenn IEnumerable sofort verbraucht wird [1], dieselbe Objektinstanz zurückgegeben wird (die Kosten eines Konstruktoraufrufs werden gespart).

Im Folgenden ist der IL durch den 4,5-Compiler generiert:

.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 

Beachten Sie die zwei Anrufe von dem bisherigen Verfahren werden nun durch System.Environment::get_CurrentManagedThreadId() ersetzt, die eine Eigenschaft 4.5 .NET hinzugefügt ist.

Da das 4.5-Upgrade den 4.0 C# -Compiler (csc.exe) überschreibt, verwendet für Version 4.0 auf Ihrem Computer kompilierter Code die neue IL-Vorlage und wird nicht auf einer Vanille 4.0-Installation ausgeführt, es sei denn, Sie haben die .NET 4.0-Referenz Assemblies [2], die bewirken, dass der Compiler die alte Version der IL generiert.

[1] Das heißt, das erste Mal, dass es in dem Thread verbraucht wird, der es erstellt hat (z. B. in einer foreach-Anweisung).

[2] Es ist tatsächlich möglich, den .NET 4.0-Compiler aus dem .NET Framework-Installationsprogramm zu extrahieren und Ihre Projektdateien zu ändern, um Ihren Code damit zu kompilieren. Dies könnte eine andere Möglichkeit sein, das Problem zu lösen, aber es ist eine lange Geschichte, und ich werde hier nicht ins Detail gehen

Verwandte Themen