Condividi tramite


Confronto tra classe, componente e controllo

Questo argomento fornisce le definizioni di componente e controllo. Le informazioni riportate possono essere utilizzate per determinare se utilizzare una classe componente o controllo.

Nota

Questo argomento è relativo alle classi ASP.NET e di Windows Form. Non vengono trattate le classi WPF. Per informazioni sulla creazione dei controlli WPF, vedere Control Authoring Overview.

Nell'elenco che segue vengono fornite indicazioni di massima per l'implementazione.

  • Se la propria classe fa uso di risorse esterne ma non verrà utilizzata su un'area di progettazione, implementare System.IDisposable o derivare da una classe che implementa direttamente o indirettamente IDisposable.

  • Se la propria classe verrà utilizzata su un'area di progettazione, quale la finestra di progettazione di Windows Forms o di Web Form, implementare System.ComponentModel.IComponent o derivare da una classe che implementa direttamente o indirettamente IComponent. IComponent estende IDisposable, pertanto un tipo IComponent è sempre un tipo IDisposable. Il tipo IComponent offre prestazioni leggermente ridotte rispetto a un tipo IDisposable che non è IComponent. Tale svantaggio è solitamente compensato dalla possibilità di posizionare il tipo IComponent sia in fase di progettazione che in fase di esecuzione. Il posizionamento è descritto più avanti in questo argomento.

  • Per ottenere una classe che sia progettabile (utilizzata su un'area di progettazione) e di cui venga eseguito il marshalling per riferimento, è possibile derivare da System.ComponentModel.Component. [T:System.ComponentModel.Component ] è l'implementazione di base di un tipo IComponent di cui viene eseguito il marshalling per riferimento.

  • Se si desidera una classe progettabile il cui marshalling venga eseguito per valore, è possibile derivare da System.ComponentModel.MarshalByValueComponent. [T:System.ComponentModel.MarshalByValueComponent ] è l'implementazione di base di un tipo IComponent di cui viene eseguito il marshalling per valore.

  • Se si desidera inserire un tipo IComponent nella gerarchia del modello a oggetti e non è possibile derivare da un'implementazione di base quale Component o MarshalByValueComponent a causa dell'ereditarietà singola, implementare IComponent.

  • Una classe che può essere utilizzata su un'area di progettazione e dispone di un'interfaccia utente è un controllo. I controlli devono derivare direttamente o indirettamente da una delle classi di controlli di base: System.Windows.Forms.Control o System.Web.UI.Control.

    Nota

    Se una classe non può essere utilizzata su un'area di progettazione né utilizza risorse esterne, non occorre un tipo IComponent o IDisposable.

In seguito sono riportate le definizioni di componente, controllo, contenitore e sito.

Componente

In .NET Framework un componente è una classe che implementa l'interfaccia System.ComponentModel.IComponent o che deriva direttamente o indirettamente da una classe che implementa IComponent. In programmazione il termine componente è solitamente utilizzato per indicare un oggetto riutilizzabile in grado di interagire con altri oggetti. Un componente .NET Framework, oltre a soddisfare tali requisiti generali, fornisce funzionalità quali il controllo di risorse esterne e il supporto della fase di progettazione.

Controllo di risorse esterne

L'interfaccia IComponent estende l'interfaccia IDisposable, il cui contratto include un metodo denominato Dispose. Nella nuova implementazione del metodo Dispose un componente deve rilasciare le risorse esterne in modo esplicito. In tal modo è possibile liberare le risorse in modo deterministico, diversamente da quanto avviene con il rilascio predefinito non deterministico ottenibile tramite Garbage Collection. Gli sviluppatori devono propagare Disposein tutta la gerarchia di contenimento, affinché anche i figli del componente liberino le proprie risorse. È inoltre necessario che gli eventuali componenti derivati invochino il metodo Dispose della propria classe base.

Nota

Anche se Dispose fornisce il controllo esplicito sulle risorse, è preferibile che lo sviluppatore provveda a liberarle comunque in modo implicito tramite il finalizzatore (distruttore), così da evitare la perdita permanente di risorse che si verifica se un utente non chiama Dispose sul componente.

Nell'esempio che segue viene illustrata la tecnica per l'implementazione di Dispose in un componente di base e in un componente derivato.

public class BaseComponent : IComponent {

   // IComponent extends IDisposable.
   public void Dispose() {
        Dispose(true);
     GC.SuppressFinalize(this); 
      }

   protected virtual void Dispose(bool disposing) {
      if (disposing) {
          // Free other state (managed objects).
      }
      // Free your own state (unmanaged objects).
   }

   // Simply call Dispose(false).
      ~BaseComponent(){
      Dispose (false);
   }
}
   
// Derived component.
public class DerivedComponent : BaseComponent {
   
   protected override void Dispose(bool disposing) {
      if (disposing) {
      // Free other state.
      }
      // You must invoke the Dispose method of the base class.
      base.Dispose(disposing);
      // Free your own state.
      ...
   }
   // No finalizer/destructor.
   // No Dispose() method.
}

   
' Design pattern for a base class.
Public Class BaseComponent
   Implements IComponent
   ' Implement IDisposable
   Public Overloads Sub Dispose() 
      Dispose(True)
      GC.SuppressFinalize(Me)
   End Sub

   Protected Overloads Overridable Sub Dispose(disposing As Boolean)
      If disposing Then
         ' Free other state (managed objects).
      End If
      ' Free your own state (unmanaged objects).
      ' Set large fields to null.
   End Sub

   Protected Overrides Sub Finalize()
      ' Simply call Dispose(False).
      Dispose (False)
   End Sub
End Class

' Design pattern for a derived component.
Public Class DerivedComponent
   Inherits BaseComponent

   Protected Overloads Overrides Sub Dispose(disposing As Boolean) 
      If disposing Then 
         ' Release managed resources.
      End If
      ' Release unmanaged resources.
      ' Set large fields to null.
      ' Call Dispose on your base class.
      Mybase.Dispose(disposing)
   End Sub
   ' The derived class does not have a Finalize method
   ' or a Dispose method with parameters because it inherits
   ' them from the base class.
End Class

Supporto della fase di progettazione

Un'importante funzionalità dei componenti di .NET Framework è quella che li rende manipolabili in fase di progettazione. In altre parole, una classe che riveste il ruolo di componente può essere utilizzata in un ambiente per lo sviluppo rapido di applicazioni (RAD, Rapid Application Development) quale Visual Studio. I componenti possono essere aggiunti alla casella degli strumenti di Visual Studio, trascinati e rilasciati su un form e modificati su una superficie di progettazione. Si noti che il supporto di base per la fase di progettazione per i tipi IComponent è incorporato in .NET Framework. La fruizione di tale supporto non richiede allo sviluppatore di componenti alcun intervento aggiuntivo.

Per ulteriori informazioni sul supporto di base in fase di progettazione, vedere Attributi per componenti in fase di progettazione e Estensione del supporto in fase di progettazione.

Hosting di un componente

È possibile collocare i componenti in un contenitore (definito più avanti in questo argomento). Quando il componente viene posizionato, interagisce con il contenitore tramite il relativo sito (definito più avanti in questo capitolo) e può interrogarlo e richiederne i servizi. Per garantire il rilascio delle risorse all'atto della dismissione del contenitore, occorre che quest'ultimo implementi l'interfaccia IDisposable. Nella propria implementazione del metodo Dispose è necessario che il contenitore rilasci tutte le risorse impegnate e invochi il metodo Dispose di ciascuno dei componenti in esso contenuti.

Il contenimento è logico e non richiede una rappresentazione visiva. Un contenitore del livello intermedio che ospita componenti per database costituisce un esempio di contenimento non visivo. Il contenimento visivo viene rappresentato nella finestra di progettazione di Windows Form e di Web Form di Visual Studio. L'area di progettazione è un contenitore che ospita il componente form (in Web Form, il componente pagina).

Marshalling di un componente

È possibile distinguere tra componenti gestibili da remoto o meno. Il marshalling dei componenti gestibili da remoto viene effettuato per riferimento o per valore. Il marshalling riguarda l'invio di oggetti attraverso limiti quali i Domini applicazione (processi leggeri), i processi e perfino i computer. Quando il marshalling di un oggetto viene effettuato per riferimento, viene creato un proxy che effettua chiamate remote all'oggetto. Quando il marshalling di un oggetto viene effettuato per valore, una copia serializzata dell'oggetto viene inviata oltre i limiti del caso.

Il marshalling dei componenti gestibili da remoto che incapsulano risorse di sistema (di grandi dimensioni) o che esistono come istanza singola deve essere effettuato per riferimento. La classe di base dei componenti il cui marshalling viene effettuato per riferimento è System.ComponentModel.Component. Tale classe base implementa IComponent e deriva da MarshalByRefObject. Molti componenti della libreria di classi .NET Framework derivano da Component, compresi System.Windows.Forms.Control (la classe base dei controlli Windows Form), System.Web.Services.WebService (la classe base dei servizi Web XML creati utilizzando ASP.NET) e System.Timers.Timer (una classe che genera eventi ricorrenti).

Il marshalling dei componenti gestibili da remoto che detengono solo uno stato deve essere effettuato per valore. La classe di base dei componenti il cui marshalling viene effettuato per valore è System.ComponentModel.MarshalByValueComponent. Tale classe base implementa IComponent e deriva da Object. I pochi componenti della libreria di classi .NET Framework che derivano da MarshalByValueComponent sono tutti compresi nello spazio dei nomi System.Data (DataColumn, DataSet, DataTable, DataView e DataViewManager).

Nota

Le classi base degli oggetti il cui marshalling viene effettuato per valore e per riferimento sono rispettivamente Object e MarshalByRefObject, ma le corrispondenti classi derivate sono denominate MarshalByValueComponent e Component. La logica che ispira il criterio di denominazione assegna al tipo più usato il nome più semplice.

Se un componente non verrà gestito da remoto, non lo si dovrà derivare dall'implementazione base di Component bensì direttamente da IComponent.

Controllo

Un controllo è un componente che fornisce capacità di interfaccia utente. .NET Framework fornisce due classi base per i controlli: una per i controlli Windows Form del lato client e l'altra per i controlli server ASP.NET. Queste classi sono System.Windows.Forms.Control e System.Web.UI.Control. Tutti i controlli nella libreria di classi .NET Framework derivano direttamente o indirettamente da queste due classi. System.Windows.Forms.Control deriva da Component e fornisce esso stesso funzionalità di interfaccia utente. System.Web.UI.Control implementa IComponent e fornisce l'infrastruttura sulla quale è facile aggiungere funzionalità di interfaccia utente.

Nota

Tutti i controlli sono componenti ma non è vero il contrario.

Contenitore e sito

Se si stanno sviluppando componenti e controlli per Windows Form o per pagine Web Form (pagine ASP.NET), non occorre implementare contenitori o siti. Le finestre di progettazione di Windows Form e di Web Form sono contenitori di Windows Form e di controlli server ASP.NET. I contenitori forniscono servizi ai componenti e ai controlli da essi ospitati. In fase di progettazione, i controlli vengono collocati nella finestra di progettazione e ricevono da questa servizi. Per completezza, di seguito sono riportate le definizioni di contenitore e sito.

  • Container
    Un contenitore è una classe che implementa l'interfaccia System.ComponentModel.IContainer o deriva da una classe che la implementa. Un contenitore contiene solitamente uno o più componenti denominati componenti figli del contenitore.

  • Site
    Un sito è una classe che implementa l'interfaccia System.ComponentModel.ISite o deriva da una classe che la implementa. I siti vengono forniti da un contenitore per la gestione e la comunicazione con i propri componenti figli. Contenitore e sito sono solitamente implementati insieme.

Vedere anche

Concetti

Cenni preliminari sulle proprietà

Attributi per componenti in fase di progettazione

Altre risorse

Sviluppo di controlli Windows Form personalizzati con .NET Framework

Sviluppo di controlli server ASP.NET personalizzati

Estensione del supporto in fase di progettazione

Cronologia delle modifiche

Data

Cronologia

Motivo

Luglio 2010

Aggiunta di una nota sul fatto che questo argomento è relativo solo a Windows Form.

Commenti e suggerimenti dei clienti.