11

Ho notato di recente alcuni comportamenti con Visual Studio Designer (C#) che non capisco e mi chiedevo se qualcuno potesse chiarire ...Perché l'IDE di Visual Studio a volte inizializza l'oggetto "this.components: e altre volte no?

Uno alcuni dei miei Windows Forms, la prima linea del designer ha generato codice legge;

this.components = new System.ComponentModel.Container(); 

Quando questo è il caso, il metodo Dispose, nello stesso file di progettazione, la Dispose metodo pone due chiamate "Dispose" all'interno del caso "se" condizione come segue:

protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
      components.Dispose(); 
      base.Dispose(disposing); 
     } 
    } 

, ad esempio non viene chiamato nulla a meno che lo smaltimento sia vero, e le componenti non siano nulle.

Su alcune altre forme, manca quella prima riga nel codice generato dal designer. In questi casi la chiamata base.Dispose è fuori dalla condizione di "se" in quanto tale ...

protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
      components.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

ho notato questo mentre rintracciare un bug con una forma non di chiusura, in cui this.components era nullo, ma la chiamata base.Dispose era dentro quella condizione (ho il sospetto che il codice stilista era stato manomesso, ma questa è un'altra storia.

cosa controlla questo comportamento?

(Alcune forme precedenti del progetto sono stati creati in VS 2005 e ora usiamo VS 2008 - indizio?)

risposta

4

Questo è un comportamento riproducibile. Quando si crea un nuovo modulo, esso inizia con uno scheletro che include la chiamata del costruttore this.components. Quando si aggiunge un componente (ad esempio un timer) e lo si rimuove, il progettista rigenera il codice, ora senza la chiamata del costruttore. Questo non è un bug.

FWIW, il codice di scheletro è generato da Common7\IDE\ItemTemplates\CSharp\Windows Forms\1033\Form.zip\form.designer.cs

Vedendo la chiamata base.Dispose() all'interno della istruzione if() è un bug. Questo potrebbe essere autoindotto. O potrebbe essere una versione beta del codice scheletro. VS2005 ha ragione. Controllare la cartella ItemsTemplatesCache.

+0

Grazie nobugz. Ho avuto la possibilità di provare anche questo scenario in VS2005. Va bene. Posso solo supporre, come dici tu, che questo è stato "autoindotto". –

+0

"ora senza la chiamata del costruttore". Quindi, qual è il punto in '(components! = Null)' controlla se non c'è l'inizializzazione di 'components' da nessuna parte? Chi, quando e dove inizializza i 'componenti'? BTW, è arrivato da VS2010, .NET4.0 – Fulproof

+0

Sembra che tu abbia una nuova domanda. Puoi chiederlo cliccando sul pulsante Ask Question. –

1

Interessante problema tecnico! Sembra davvero un bug in una versione del designer/template. Naturalmente, se si pensa il codice stilista era stato manomesso, tutte le scommesse sono abbastanza-off molto comunque ...

Tuttavia, in VS2008, genera la versione indubbiamente corretta:

if (disposing && (components != null)) 
{ 
    components.Dispose(); 
} 
base.Dispose(disposing); 

Quindi la base Dispose(...) viene chiamato. Sfortunatamente VS2005 non è stato utile per testarlo, sfortunatamente. Tuttavia - non inizializzare i componenti fino a quando non deve - la dichiarazione è:

private System.ComponentModel.IContainer components = null; 

E poi se è necessario, è popolato in InitializeComponent:

private void InitializeComponent() 
{ 
    this.components = new System.ComponentModel.Container(); 
    //... 
} 

Credo che con questo costrutto deve solo mantenere InitializeComponent (e non i campi stessi).

+0

Nemmeno Marc. Dovrò provarlo a casa stasera. Grazie. –

+0

"se pensi che il codice del designer sia stato manomesso" - sono io perché non capisco come moderarlo! – Fulproof

0

Ho visto accadere questo, e ho anche ricevuto occasionalmente avvisi dal metodo Dispose sui componenti che non hanno mai assegnato il valore o non sono stati definiti.

penso che sia una combinazione di due cose:

  1. Leggermente diversa generazione di codice tra le versioni di Visual Studio
  2. Il metodo Dispose viene generato solo se non ce n'è uno già presente nel file, mentre InitializeComponent (e dichiarazioni associate) viene generato ogni volta

Ciò risulta in una sezione InitializeComponent/dichiarazioni che è out-of-whack con il metodo Dispose.

+0

"tra le versioni di Visual Studio" - è venuto qui dalla creazione di nuove applicazioni Windows Form in VS2010, .NET4.0 senza utilizzare altre versioni (sebbene UI abbia VS2008 installato su PC) – Fulproof

3

6 anni più tardi e questo problema si verifica ancora. Sono riuscito a rintracciare almeno una causa perché ciò accada.

Quando si verifica se il componente ha un costruttore che accetta un IContainer, System.ComponentModel.Design.Serialization.ComponentCodeDomSerializer memorizza nella cache un riferimento al tipo di IContainer per il progetto. Se si salva un oggetto per un altro progetto all'interno della stessa soluzione, o forse quando sono stati apportati altri tipi di modifiche nel progetto, ComponentCodeDomSerializer non può più trovare il costruttore poiché il tipo di IContainer non è più uguale al tipo memorizzato nella cache.

Se questo sta accadendo molto per il tuo progetto, c'è una brutta soluzione. Aggiungi questo VB o C#VisualStudioWorkaroundSerializer alla tua soluzione. Quindi aggiungi l'attributo DesignerSerializer(GetType(VisualStudioWorkaroundSerializer), GetType(CodeDomSerializer)) al tuo componente. Ogni volta che il componente viene salvato, questo serializzatore personalizzato rileva il problema, lo corregge e obbliga a salvare nuovamente ogni volta che si verifica questo problema.

Problemi correlati