2015-01-20 13 views
5

W poniższym wywołaniu MessageBox.Show pojawia się komunikat "Wewnętrzny". Czy to błąd?Control.Invoke rozpakowuje wyjątek zewnętrzny i propaguje wewnętrzny wyjątek zamiast:

private void Throw() 
{ 
    Invoke(new Action(() => 
    { 
     throw new Exception("Outer", new Exception("Inner")); 
    })); 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    try 
    { 
     Throw(); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); // Shows "Inner" 
    } 
} 
+1

Zauważam, że 'await Task.Run()' nie jest istotny. Powinieneś go pominąć w swoim pytaniu, ponieważ służy jedynie odwróceniu uwagi od problemu, o który pytasz. –

+0

To jest interesujące. Jeśli dodamy kolejny wewnętrzny wyjątek, to nam to również zapewni. – Chris

+0

Flagi: starają się właściwie przeczytać pytanie przed oznaczeniem go jako duplikatem [tego innego] (http://stackoverflow.com/questions/15704711/how-can-i-use-control-invoke-to-throw- an-exception-that-will -ont-be-ignored)? – Juan

Odpowiedz

5

musiałem spojrzeć na źródło odniesienia dla System.Windows.Forms.Control, a kod, który zajmuje się Invoke wygląda następująco:

try { 
    InvokeMarshaledCallback(current); 
} 
catch (Exception t) { 
    current.exception = t.GetBaseException(); 
} 

GetBaseException:

public virtual Exception GetBaseException() 
{ 
    Exception inner = InnerException; 
    Exception back = this; 

    while (inner != null) { 
     back = inner; 
     inner = inner.InnerException; 
    } 

    return back; 
} 

więc widocznie to tak przez projekt. Komentarze w źródle nie zawierają żadnego wyjaśnienia, dlaczego tak robią.

EDIT: Niektóre witryny, która już nie ma roszczeń ten komentarz pochodzi od faceta w firmie Microsoft:

Na podstawie winform comfirmation w rekordzie, nasza analiza jest poprawne od przyczynę i to zachowanie jest zamierzony. Powodem było to, że użytkownik nie widział zbyt wiele mechanizmów wewnętrznych Windows.Forms. Dzieje się tak, ponieważ domyślne okno dialogowe błędu winformu również wykorzystuje Application.ThreadException, aby wyświetlić szczegóły wyjątku. .Net Winform zespół przycina inne informacje o wyjątkach, dzięki czemu domyślny błąd w oknie dialogowym nie wyświetli wszystkich szczegółów dla użytkownika końcowego.

Również niektóre MSFT sugerowały zmianę tego zachowania. Jednak .Net Zespół Winform uważa, że ​​zmiana wyjątku na throw jest przełamującą zmianą iz tego powodu WinForms będzie nadal wysyłać najbardziej wewnętrzny wyjątek do obsługi aplikacji Application.ThreadException.

+1

Zauważyłem, że istnieją również dwa obecnie oczyszczone raporty Connect dotyczące tematu, wcześniej pod adresami URL http://connect.microsoft.com/VisualStudio/feedback/details/386582/control-invoke-exception-handling i http: // connect.microsoft.com/VisualStudio/feedbackdetail/view/433765/control-invoke-throws-exception-getbaseexception-rather-than-temp-exception- (jeśli spróbujesz przejść do tych linków, strona internetowa zgłasza, że ​​strony są znika lub jest zabronione). Możesz zobaczyć małe fragmenty każdego z nich, wyszukując MSDN za pomocą "wyjątku wewnętrznego control.invoke" i przeglądając podsumowania. –

+0

Dobre wyniki. Nie można jednak znaleźć tego kodu w ILSPY. – Juan

+1

@Juan Sprawdź 'InvokeMarshaledCallbacks()' pod 'System.Windows.Forms.Control'. – Chris

Powiązane problemy