2013-03-22 15 views
35

Co może spowodować następujący wyjątek?System.MissingMethodException Int32 System.Environment. get_CurrentManagedThreadId()

System.MissingMethodException Int32 System.Environment.get_CurrentManagedThreadId() 

Sposób ten wydaje się być połączenie generowane przez kompilator C# metod dających IEnumerable<>.

.NET Framework v4.0 x86 jest zainstalowany i binarna jest kompilowany do v4.0 Wszelkie procesora.

+1

ten pojawia się również jako „Metoda nie znaleziono:' Int32.System.Environment.get_CurrentManagedThreadId() '. – EBarr

Odpowiedz

52

CurrentManagedThreadId jest .NET 4.5 nieruchomość, więc trzeba będzie 4,5 do uruchomienia kodu. Aby uzyskać informacje o tym, jak może wystąpić ten problem, należy zapoznać się z artykułem Iterator blocks, missing methods, and .NET 4.5.

W skrócie:

Jeśli budować swoją aplikację (ukierunkowane na .NET 4.0) w systemie z zainstalowanym .NET 4.5, 4.5 użyje jako podstawa do obliczania, ponieważ .NET Framework 4.0 jest zawsze nadpisywane przez .NET 4.5.

Jeśli twoja aplikacja używa również yield return, zawiedzie się na systemach z zainstalowanym tylko 4.0, ponieważ implementacja tej instrukcji używa nowej właściwości, gdy została skompilowana dla 4.5 Framework.

Aby rozwiązać ten problem, upewnij się, że system kompilatora ma zestawy referencyjne 4.0.

+0

Ostatnio patrzyłem na ten problem i zauważyłem, że serwer kompilacji z 4.6.1 zainstalował stworzony kod, w zależności od 'Thread.CurrentThread.ManagedThreadId' ponownie. Nie udało mi się znaleźć tego udokumentowanego w Internecie, ale sugeruje to, że MS naprawił ten problem w późniejszych wersjach. – Iain

3

wysyłającego floele „s odpowiedź; Aby uzyskać więcej informacji, oto krótka analiza problemu:

Gdy kompilator przetwarza blok iteracyjny zwracający wartość IEnumerable, generuje prywatną klasę IEnumerable w celu zachowania logiki iteracji. Jest to początek IL generowane przez jego metody GetEnumerator przez kompilator 4.0:

.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 

Wskazówka rozmowy do System.Threading.Thread::get_CurrentThread() i System.Threading.Thread::get_ManagedThreadId();. Wygenerowana metoda wykorzystuje to do wykonania optymalizacji, gdzie, jeśli IEnumerable zostanie zużyty natychmiast [1], zwracana jest ta sama instancja obiektu (zapisywanie kosztu wywołania konstruktora).

Poniżej IL wygenerowany przez kompilator 4.5:

.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 

Wskazówka dwa telefony od poprzedniej metody są teraz zastąpione przez System.Environment::get_CurrentManagedThreadId(), który jest własnością dodany w .NET 4.5.

Ponieważ aktualizacja 4.5 powoduje nadpisanie kompilatora 4.0 C# (csc.exe), kod skompilowany dla wersji 4.0 na twoim komputerze będzie używał nowego szablonu IL i nie będzie działał na instalacji wanilii 4.0, chyba że posiadasz .NET 4.0 Złożenia [2], które spowodują, że kompilator wygeneruje starą wersję IL.

[1] Oznacza to, że po raz pierwszy, że jest zużywana na gwint, który je wygenerował (na przykład w foreach).

[2] Jest to rzeczywiście możliwe, aby wyodrębnić .NET 4.0 kompilatora od instalatora .NET Framework i modyfikować pliki projektu do kompilacji kodu z tym. To może być kolejny sposób, aby rozwiązać ten problem, ale to długa historia i nie będę wchodzić w szczegóły tutaj

Powiązane problemy