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
Questo si apre anche come "Metodo non trovato:' Int32.System.Environment.get_CurrentManagedThreadId() '. – EBarr