2009-10-08 10 views
7

Se si dispone di un pennello e la penna come in:Come gestire gli oggetti usa e getta a cui non si fa riferimento?

Brush b = new SolidBrush(color); 
Pen p = new Pen(b); 

e smaltire in questo modo:

b.Dispose(); 
p.Dispose(); 

Come ti smaltire se fosse:

Pen p = CreatePenFromColor(color) che creerebbe il pennello e penna per te? Non riesco a smaltire il pennello all'interno di questo metodo, giusto?

È un metodo da non utilizzare con gli oggetti monouso?

EDIT: Che cosa intendo dire, come smaltire la SPAZZOLA?

+0

o.O non sapevo che Pennello e penna implementati IDisposable ... –

+0

lol, lo fa certamente. –

+0

Ma dove si riferisce effettivamente questo pennello? Perché (e dove) lo stai creando se stai restituendo una penna solo come risultato del metodo? – Groo

risposta

9

È il lavoro del metodo CreatePenFromColor per eliminare l'istanza di Pennello.Non è ovvio a colpo d'occhio, ma se si scava nell'implementazione della classe Pen si vedrà che non si blocca sull'istanza di Brush passata. Invece lo usa solo per calcolare alcuni valori. Quindi non c'è alcun motivo per cui l'istanza di Brush vada oltre la chiamata a CreatePenFromColor e il metodo dovrebbe eliminare l'istanza.

+0

Grazie Jared, non lo sapevo. –

+0

Questo non è necessariamente vero. il costruttore Pen passa l'handle del pennello a 'GdipCreatePen2'. Non so se 'GdipCreatePen2' ha bisogno del pennello per rimanere vivo (la funzione è appena documentata), ma immagino che lo faccia.Ricorda che il pennello potrebbe essere un "TextureBrush" con un'immagine e non vorresti che la penna realizzasse una copia separata dell'immagine in memoria in modo da poter disporre del pennello. – SLaks

+1

@Slaks, GdipCreatePen2 AFAIK non lo richiede per rimanere in vita. Ho esaminato la documentazione molto limitata ed è solo necessario impostare la penna, non mantenerla. – JaredPar

6

È ancora necessario smaltirlo quando hai finito.

Ad esempio, è possibile chiamare in questo modo:

using (Pen p = CreatePenFromColor(color)) 
{ 
    // do something 
} 

Se un metodo restituisce un oggetto IDisposable, è vostro dovere di disporre di esso.

[Modifica] Ora ho ottenuto la domanda: si sta utilizzando il costruttore Pen (Brush b).

a. In questo caso, sembra che la penna non ha bisogno l'istanza pennello dopo costruttore, in modo che il metodo potrebbe essere la seguente:

public Pen CreatePenFromColor(Color c) 
{ 
    using (Brush b = new SolidBrush(c)) 
    { return new Pen(b); } 
} 

b. Perché non usare semplicemente Pen(Color color)?

public Pen CreatePenFromColor(Color c) 
{ 
    return new Pen(c); 
} 

c. (per quanto riguarda il commento) Se la Penna trattiene un riferimento al Pennello internamente, allora non si potrebbe disporne prima di aver terminato con la Penna. In tal caso, vorrei andare per una classe che avrebbe fatto il lavoro per me:

public class PenHelper : IDisposable 
{ 
    private readonly Brush _brush; 
    public PenHelper(Color color) 
    { 
     _brush = new SolidBrush(color); 
    } 

    public Pen CreatePen() 
    { 
     return new Pen(_brush); 
    } 

    public void Dispose() 
    { 
     _brush.Dispose(); 
    } 
} 

e quindi utilizzarlo in questo modo:

using (PenHelper penHelper = new PenHelper(Color.Black)) 
{ 
    using (Pen pen = penHelper.CreatePen()) 
    { 
      // do stuff 
    } 
} 

Diniego: IDisposable non è implementata secondo le linee guida, ma piuttosto per la sola dimostrazione. Inoltre, l'intero esempio viene utilizzato solo per mostrare come incapsulare un riferimento quando necessario. Dovresti andare a Pen (colore), ovviamente.

+0

+1 per "perché le persone creano pennelli per creare penne da?!?" –

+0

Grazie. Nell'esempio a, il pennello b verrebbe eliminato non appena viene restituita la penna, giusto? Se la penna avesse un riferimento al pennello b all'interno, farebbe un esempio? Mi stavo solo chiedendo. –

+0

Grazie per l'esempio esteso. –

0

Quando un metodo rilascia un'istanza IDisposable, passa simultaneamente alla responsabilità di gestione a vita.

Ora è la responsabilità del chiamante di smaltire l'oggetto dopo l'uso. Se quell'oggetto contiene altri oggetti IDisposabili, per convenzione dobbiamo aspettarci che il contenitore disponga correttamente dei suoi figli quando lo smaltiamo, altrimenti implicherebbe un bug nel contenitore.

Nel vostro esempio concreto, dovreste aspettarvi che la Penna smaltisca la sua istanza di Pennello interna quando la smaltite.

+0

Anche i colori sono usa e getta? –

+1

No, il colore è una struttura. – Groo

+1

@Joan Venge: 'Typo' - L'ho corretto in concomitanza con il tuo commento ... –

2

Il tuo problema non ha una soluzione generale.

Nel tuo esempio specifico, non è un problema, perché Pen ha un costruttore che prende direttamente un Colore.

Alcune classi disporranno direttamente i parametri del costruttore (in particolare le classi relative al flusso); controlla ogni classe in Reflector.

Se la classe restituita eredita da Component, è possibile aggiungere un gestore all'evento Disposed.

Se la classe che si sta restituendo non è sigillata, è possibile creare una versione ereditata che dispone l'oggetto da cui è stato creato.

Infine, se lo si desidera, è possibile creare una classe wrapper che contiene l'oggetto che si sta restituendo e dispone il parametro del costruttore. Tuttavia, sarebbe molto confuso e non lo consiglierei.

+0

Grazie, non sapevo che Pen potesse prendere un Colore direttamente. È divertente perché vedo un sacco di codice che crea il pennello e la penna separatamente e quindi uso solo la penna per dipingere. –

+0

Allora dovresti accettare questa risposta. – SLaks

+0

Sì, lo fa. Semplicemente non c'è una soluzione generale pulita. – SLaks

1

Uno dei miei problemi con molte delle classi relative alla grafica è che non esiste un modello coerente per la gestione di tali problemi. Ciò che è veramente necessario è un mezzo per implementare il conteggio parziale dei riferimenti. Non nello stile COM, dove il passaggio dei riferimenti richiede il costante aumento dei conteggi dei riferimenti, ma in un modo in base al quale, dato un oggetto grafico IDisposable, è possibile richiedere un'altra istanza che condivide la stessa risorsa sottostante. Le risorse stesse verrebbero incapsulate in un oggetto condiviso con un contatore di riferimento. La creazione di un'altra istanza di riferimento incrementerebbe il contatore; chiamare Dispose su un'istanza di riferimento lo ridurrebbe. Ciò eviterebbe il 95% del sovraccarico del conteggio dei riferimenti, pur mantenendo il 99% del vantaggio.

Problemi correlati