2017-01-31 1 views
0

ich mit diesem ordentlichen Code aus CodeprojectEndInvoke() nicht zurück (Schleife Deadlock?)

Es ein bisschen herum nur spielen bin ist eine sichere Aufruf Methode für Kontrollen:

public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke 
{ 
    if (isi.InvokeRequired) { 
     IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
     object endResult = isi.EndInvoke(result); return (TResult)endResult; 
    } 
    else 
     return call(isi); 
} 

Szenario 1: Windows Forms-App mit einem WebBrowser-Steuerelement. Dieser Aufruf gibt, was es soll (das zurückkehrende Ergebnis egal ist im Moment nur für die Prüfung um):

private void button1_Click(object sender, EventArgs e) 
{ 
    Thread thread = new Thread(new ThreadStart(StartStuff)); 
    thread.Start(); 
} 

private void StartStuff() 
{   
    var document = webBrowser1.SafeInvoke(o => o.Document);  
} 

So weit so gut, gute Arbeit vom Typ, der dieses Fragment von sicherem Aufruf erstellt.

Szenario 2: Als nächstes möchte ich einige Komponententests ausführen, die einige WebBrowser-basierte Sachen verarbeiten. Dieser kleine Test soll dies demonstrieren:

[Test, Category("Thread Safety")] 
public void TestIfThreadRaisesException() 
{ 
    /* create STA thread where the browser will live and die in */ 
    Thread thread = new Thread(RunSTAContent); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    thread.Join(); 
} 

private static void RunSTAContent() 
{ /* simulate cross thread access to control */ 
    var stdBrowser = new System.Windows.Forms.WebBrowser(); 
    Task.Run(async() => await RunUnProblematicContent(stdBrowser)).Wait(); 
} 

private static async Task RunUnProblematicContent(System.Windows.Forms.WebBrowser browser) 
{ 
    await Task.Delay(1000); 
    var doc = browser.SafeInvoke(o => o.Document); 
    //... 
} 

Auf diese Weise erhalte ich einen unendlichen Aufruf SafeInvoke, genauer gesagt es endet hier:

object endResult = isi.EndInvoke(result); 

Haben Sie einen Hinweis, warum der Aufruf nie endet? Ist es mehr wegen meines selbstgemachten STA-Threads? Könnte es in Verbindung mit NUnit ein Problem mit dem Console Runner sein?

+3

Es gibt keine Nachrichtenschleife auf dem STA-Thread ('Application.Run'), die für' Invoke' Unterstützung obligatorisch ist. –

+0

Ohhh, das scheint absolut plausibel, und natürlich ... Ich werde es morgen überprüfen und Feedback geben. Vielen Dank –

+2

@ stev-e: Nebenbei bemerkt, ich rate immer die Verwendung von 'InvokeRequired'. Der "Safe Invoke" -Ansatz ist ein Anti-Pattern. Code sollte immer wissen, wo er läuft, und Thread-Sprünge sollten explizit sein. –

Antwort

0

Wie in Ivans Kommentar erwähnt, fehlte die Nachrichtenschleife. Ich kam in dieser Klasse, die ich für diesen Zweck verwenden kann :)

MessageLoopApartment