2011-02-09 15 views
5

Capisco perché i controlli della GUI hanno affinità di thread.Perché i controlli WinForms/WPF non utilizzano Invoke internamente?

Ma perché i controlli non utilizzano la chiamata internamente nei propri metodi e proprietà?

Ora si hanno a che fare cose come questa solo per aggiornare TextBox valore:

this.Invoke(new MethodInvoker(delegate() 
{ 
    textBox.Text = "newValue"; 
} 

Mentre si utilizza solo textBox.Text = "newValue"; sarebbe sufficiente a rappresentare la stessa logica.

Tutto ciò che avrebbe dovuto essere fatto è cambiare textBox.Text logica da questo (pseudocodice):

public string Text 
{ 
    set 
    { 
     if(!this.InvokeRequired) 
      // do the change logic 
     else 
      throw new BadThreadException(); 
    } 
} 

A tal:

public string Text 
{ 
    set 
    { 
     if(!this.InvokeRequired) 
      // do the change logic 
     else 
      this.Invoke(new MethodInvoker(delegate() 
      { 
       // do the change logic 
      } 
    } 
} 

Lo stesso vale per getter e metodi.

sto certamente non proponendo di eliminare Invoke/BeginInvoke, sto solo chiedendo perché i controlli non si fanno se stessi passare il filo necessaria invece di buttare eccezione.

+0

Poiché in genere non è necessario aggiornare i controlli su un thread diverso da quello in cui sono stati creati.Fare così è un caso eccezionale, quindi devi saltare attraverso i cerchi. Non ci sarebbe quasi nessun vantaggio ad avere questo built-in. –

+0

Suppongo che ogni singolo "Invoke" implichi un sovraccarico, e se hai molti controlli che invocano automaticamente puoi incorrere in problemi di prestazioni. Lanciando l'escpetion, il sistema impone agli sviluppatori di occuparsi dei problemi di threading e di utilizzare il Dispatcher per effettuare una singola chiamata Invoke con tutte le assegnazioni all'interno. – BertuPG

risposta

9

Penso che in questo modo l'API impone agli sviluppatori di prendere una decisione esplicita ed evitare errori di programmazione non intenzionali. Qui ci sono diversi problemi che potrei venire subito:

1. Blocco di filo involontario. Se si scrive su una proprietà, il thread chiamante dovrà bloccare fino a quando il messaggio non viene elaborato dal thread dell'interfaccia utente. E se chiamare thread possiede una risorsa che il thread dell'interfaccia utente potrebbe voler acquisire, si otterrà un deadlock che è difficile da debugare (il thread chiamante tiene una risorsa e attende che il messaggio venga elaborato dal thread dell'interfaccia utente, il thread dell'interfaccia utente attende finché la risorsa non viene rilasciata)).

2. Sorprese impreviste. Se rendessimo le operazioni di scrittura implicitamente asincrone, ci imbattiamo in una situazione in cui il lettore non dovrebbe mai aspettarsi che i valori siano sempre aggiornati.

3. Impatto sulle prestazioni. Se si scrive un algoritmo intensivo che utilizza implicitamente l'invio dell'interfaccia utente, si ottengono prestazioni davvero scadenti e si è liberi di incolpare gli sviluppatori di framework. Dopo tutto hai scritto l'ordinamento che dovrebbe essere eseguito in O (n), ma per qualche motivo ci vogliono secoli per essere completato.

+1

Stavo pensando che anche queste potrebbero essere le ragioni, ma ci sono già troppe cose che riguardano i thread, quindi non credo che ciò farebbe molta differenza. –

2

Bene, a meno che nessuno dei desginer o implementatori del framework risponda, questo può essere solo ipotizzato, ma il più ovvio però che salta alla (almeno la mia) mente è la complessità . Aggiungere la logica di cambio di thread in tutti i punti rilevanti di tutti i controlli porterebbe ad un enorme aumento della loro complessità (basta immaginare tutti i test necessari per verificare il comportamento ovunque). Probabilmente non varrebbe la pena, quindi il lavoro è trasferito agli utenti dei controlli (noi) che hanno bisogno di fare questo piccolo giro in più nei casi in cui è necessario.

+0

Suppongo che sarebbe quello di contrassegnare i metodi e le proprietà con un attributo e quindi aggiungere l'interruttore di thread in fase di compilazione (o dopo - simile a cosa fa NotifyPropertyWeaver) –

+0

@mzabsky: buon punto. Sarebbe più semplice, ma sposterebbe la complessità nel compilatore, il che sarebbe comunque un cambiamento piuttosto costoso. –

Problemi correlati