2011-04-13 13 views
35

Vedere sotto per una spiegazione di ciò che sta accadendo.NET eccezione catturato è inaspettatamente nulla

Ho un problema davvero strano dove l'eccezione catturato è nullo.

Il codice utilizza MEF e cerca di segnalare errori di composizione. Usando il debugger posso vedere l'eccezione lanciata (un InvalidOperationException) ma quando viene catturata dall'ultimo blocco catch nel codice sotto la variabile ex è nullo. Questo è vero sia nel debugger che durante l'esecuzione normale del codice.

static T ResolveWithErrorHandling<T>() where T : class 
{ 
    try 
    { 
     IocContainer.Compose(Settings.Default.IocConfiguration); 
     return IocContainer.Resolve<T>(); 
    } 
    catch (ReflectionTypeLoadException ex) 
    { 
     // ... special error reporting for ReflectionTypeLoadException 
    } 
    catch (Exception ex) 
    { 
     // ex is null - that should not be possible! 
     // ... general error reporting for other exception types 
    } 
    return null; 
} 

Il codice che ho sostituito con i commenti è codice molto semplice per formattare il messaggio di errore. Non succede niente di strano.

ho cercato di modificare il codice di scoprire che effetto che potrebbe avere:

  • Se rimuovo il primo blocco catch (ReflectionTypeLoadException) l'eccezione catturato nel blocco catch finale è non è più nulla.
  • Se rilevo un altro tipo di eccezione nel primo blocco catch, l'eccezione rilevata nel blocco catch finale non è più nulla.
  • Se aggiungo un blocco catch per InvalidOperationException come primo blocco catch, l'eccezione rilevata in quel blocco non è nulla.
  • Se aggiungo un blocco catch per InvalidOperationException tra i due blocchi catch, l'eccezione rilevata in quel blocco è null.

Il progetto utilizza Code Contracts e il codice generato dal compilatore è post-elaborato per verificare i contratti. Sfortunatamente, non ho trovato un modo per sbarazzarmi di questo a scopo di test senza eseguire un intervento chirurgico importante sul progetto.

La mia soluzione attuale è quella di non intercettare ReflectionTypeLoadException e diramare invece il tipo di ex nel gestore di eccezioni generale.

Quale potrebbe essere la spiegazione di questo comportamento "impossibile"? Che succede con il blocco catch ReflectionTypeLoadException?


In modo imbarazzante, l'eccezione non è nulla e non può essere nullo per lo standard C# 15.9.5.

Tuttavia, l'utilizzo di Contratti di codice in un progetto can mess up the display of local variables in the debugger poiché il codice IL generato dal compilatore può essere riscritto dai Contratti di codice in modo che l'IL finale non sia leggermente sincronizzato con le informazioni di debug. Nel mio caso la variabile ex viene visualizzata come null anche se non lo è. La sfortunata natura della segnalazione degli errori avvenuta proprio prima della chiusura della domanda ha significato che ritenevo che l'errore di segnalazione non fosse chiamato a causa del fatto che ex era nullo e ex.Message che lanciava uno NullReferenceException nel mio blocco di cattura. Usando il debugger sono stato in grado di "verificare" che ex fosse nullo, tranne che in realtà non era nulla.

La mia confusione è stata aggravata dal fatto che un blocco catch per ReflectionTypeLoadException sembra influenzare il problema di visualizzazione del debugger.

Grazie a tutti coloro che hanno risposto.

+0

Esiste effettivamente un 'ReflectionTypeLoadException' che viene lanciato ovunque? – Jaymz

+1

Solo una nota, ma puoi gestire i diversi tipi di eccezione o stai solo segnalando lo stesso per ciascuno? Se si tratta di rapporti generici e non è possibile _handle_ l'eccezione, non sono sicuro che sarà necessario adattare le interferenze in ogni caso. –

+0

Cosa succede quando si aggiunge una cattura per InvalidOperationExecption? –

risposta

11

Appena incontrato questo stesso problema. Alla fine ho scoperto che mi catched diverse eccezioni con lo stesso nome, come hai fatto:

catch (ReflectionTypeLoadException ex) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is not null! 
    // ... 
} 

Entrambi sono chiamati 'ex'. Cambiare uno dei due nomi ha risolto questo problema per me, come:

catch (ReflectionTypeLoadException reflectionEx) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is null - that should not be possible! 
    // ... 
} 
4

È necessario verificare se a un certo punto, IocContainer rileva uno Exception ex genera ex.InnerException senza verificare se è nullo.

C# accetta felicemente throw null e termina in catch (Exception).

+4

Se si genera un'eccezione nulla (ad esempio, se "ex.InnerException' è nullo) viene invece generata una' NullReferenceException'. In C# l'eccezione rilevata non può mai essere nulla. Tranne che è nel mio caso ... –

+0

Ahh, mio ​​male, ho appena avuto un sospetto, ho impostato un test case, ho passato sopra la variabile 'ex' e ho visto" riferimento non impostato su un'istanza ", lo ho scambiato per un vero nullo. –

0

Anche io ho la stessa situazione. È successo a un bug del debugger di Eclipse. (In realtà, questa situazione può essere solo il risultato di qualche bug del debugger.)

Il riavvio di Eclipse è stato sufficiente - l'eccezione di runtime diventa normale, non nulla. Altri debugger potrebbero non essere così gentili.

4

Mi sono imbattuto nello stesso problema. L'eccezione era nulla quando veniva visualizzata nel debugger anche se veniva rilevato il tipo corretto di eccezione - UpdateException. Potrei visualizzare l'eccezione aprendo l'Exception Assistant.

Non appena si è disattivato "Esegui controllo contratto di runtime" ha rilevato eccezioni dove non è più nullo. Ho utilizzato attivamente i contratti di codice per un anno e non avevo mai visto questo problema prima di iniziare a lavorare con EF 4.1 in questo particolare progetto di recente - ma non so se EF fosse una variabile di controllo in quanto le eccezioni scoperte erano nulle .

5

Ho avuto lo stesso problema. Nel mio caso rinominare la variabile di eccezione (ad es. Ex => ex1) mi è stato permesso di rilevare eventuali eccezioni ...

1

L'eccezione non è infatti nulla, è un problema con il debugger. I contratti di codice (ccrewrite) cambiano gli opcode di IL e questo perturba il debugger, poiché gli opcode di leave.s vengono trasformati in opcode di congedo. I due codici opzionali hanno dimensioni e cambi di istruzioni diversi, ecco perché il debugger viene perso quando i nomi delle eccezioni sono uguali.

È possibile utilizzare l'eccezione $ nel debugger per risolvere il problema.

Problemi correlati