2013-03-22 4 views
35

Cosa potrebbe causare la seguente eccezione?System.MissingMethodException Int32 System.Environment. get_CurrentManagedThreadId()

System.MissingMethodException Int32 System.Environment.get_CurrentManagedThreadId() 

Questa chiamata di metodo sembra essere generato dal compilatore C# per i metodi cedendo IEnumerable<>.

.NET Framework v4.0 x86 è installato e il file binario è compilato per v4.0 Qualsiasi CPU.

+1

Questo si apre anche come "Metodo non trovato:' Int32.System.Environment.get_CurrentManagedThreadId() '. – EBarr

risposta

52

CurrentManagedThreadId è una proprietà .NET 4.5, quindi è necessario 4.5 per eseguire il codice. Vedere Iterator blocks, missing methods, and .NET 4.5 per un'analisi di come questo problema potrebbe verificarsi.

In breve:

Se si genera l'applicazione (mirati a .NET 4.0) su un sistema con .NET 4.5 installato, userà 4.5 come base per la compilazione, perché il .NET Framework 4.0 viene sempre sovrascritto da .NET 4.5.

Se l'applicazione utilizza anche yield return, avrà esito negativo su sistemi con solo 4.0 installato poiché l'implementazione di questa istruzione utilizza una nuova proprietà quando è compilata per 4.5 Framework.

Per risolverlo, assicurarsi che il proprio sistema di compilazione abbia i 4.0 assiemi di riferimento.

+0

Ho cercato a questo problema da poco e ho notato che un build server con 4.6.1 codice creato installato a seconda 'Thread.CurrentThread.ManagedThreadId' di nuovo. Non sono stato in grado di trovare questo documento ovunque online, ma questo suggerisce che MS ha risolto questo problema nelle versioni successive. – Iain

3

Secondi numero di telefono risposta; per ulteriori informazioni, ecco una breve analisi del problema:

Quando il compilatore elabora un blocco iteratore che restituisce un IEnumerable, genera una classe privata IEnumerable per contenere la logica di iterazione. Questo è l'inizio della IL generato per il suo metodo GetEnumerator dal compilatore 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 

Avviso le chiamate a System.Threading.Thread::get_CurrentThread() e System.Threading.Thread::get_ManagedThreadId();. Il metodo generato utilizza questo per eseguire un'ottimizzazione dove, se lo IEnumerable viene consumato immediatamente [1], viene restituita la stessa istanza dell'oggetto (risparmiando il costo di una chiamata del costruttore).

È il seguente IL generato dal compilatore 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 

comunicazione le due chiamate dal metodo precedente sono ora sostituiti da System.Environment::get_CurrentManagedThreadId(), che è una proprietà aggiunto NET 4.5.

Poiché l'aggiornamento 4.5 sovrascrive il compilatore 4.0 C# (csc.exe), il codice compilato per 4.0 sulla macchina utilizzerà il nuovo modello IL e non verrà eseguito su un'installazione di vanilla 4.0, a meno che non si disponga di .NET 4.0 Reference Assemblies [2], che farà sì che il compilatore generi la versione precedente dell'IL.

[1] Cioè, la prima volta che viene consumato sul thread che lo ha creato (ad esempio in un'istruzione foreach).

[2] In realtà è possibile estrarre il compilatore .NET 4.0 dal programma di installazione di .NET Framework e modificare i file di progetto per compilare il codice con quello. Questo potrebbe essere un altro modo per risolvere il problema, ma è una lunga storia e non entrerò nei dettagli qui