2009-10-08 4 views
7

Si usted tiene un pincel y la pluma como en:Cómo manejar objetos desechables que no tenemos una referencia a?

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

y disponer de ellos de esta manera:

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

¿Cómo deshacerse de él si era:

Pen p = CreatePenFromColor(color) que crearía la cepillo y pluma para ti? No puedo tirar el cepillo dentro de este método, ¿verdad?

¿Este es un método que no se debe usar con objetos desechables?

EDITAR: Lo que quiero decir es, ¿cómo se deshace del CEPILLO?

+0

O.o Yo no sabía que Brush y Pen implementan IDisposable ... –

+0

lol, ciertamente lo es. –

+0

¿Pero dónde se hace referencia a este pincel? ¿Por qué (y dónde) lo estás creando si solo estás devolviendo un Pen como resultado del método? – Groo

Respuesta

9

El método CreatePenFromColor consiste en deshacerse de la instancia de Brush.No es obvio de un vistazo, pero si profundizas en la implementación de la clase Pen verás que no se mantiene en la instancia aprobada en Brush. En cambio, solo lo usa para calcular algunos valores. Por lo tanto, no hay motivo para que la instancia de Brush viva más allá de la llamada a CreatePenFromColor y el método debería ser deshacerse de la instancia.

+0

Gracias Jared, no sabía eso. –

+0

Eso no es necesariamente cierto. el constructor de Pen pasa el asa del pincel a 'GdipCreatePen2'. No sé si 'GdipCreatePen2' necesita el pincel para mantenerse con vida (la función apenas está documentada), pero supongo que sí.Recuerde que el pincel podría ser un 'TextureBrush' con una imagen, y no le gustaría que el Pen haga una copia separada de la imagen en la memoria para que pueda tirar el pincel. – SLaks

+1

@Slaks, GdipCreatePen2 yo sepa no lo requiere para mantenerse con vida. Busqué en la documentación muy limitada y solo es necesario configurar el lápiz, no mantenerlo. – JaredPar

6

usted todavía tiene que deshacerse de él cuando haya terminado.

Por ejemplo, se puede llamar así:

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

Si un método devuelve un objeto IDisposable, es su deber de deshacerse de él.

[Editar] Ahora tengo la pregunta: estás usando el constructor Pen (Brush b).

a. En este caso, parece que la pluma no necesita la instancia cepillo después de constructor, por lo que su método podría tener este aspecto:

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

b. ¿Por qué no simplemente usar Pen(Color color)?

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

c. (En relación con el comentario) Si la pluma sostendría una referencia al cepillo internamente, entonces no sería capaz de deshacerse de él antes de que haya terminado con la pluma. En ese caso, me gustaría ir para una clase que hacer el trabajo para mí:

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(); 
    } 
} 

y luego usarlo como esto:

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

responsabilidad: IDisposable no se implementa de acuerdo con las directrices, pero más bien solo para demostración. Además, todo el ejemplo se utiliza sólo para mostrar cómo encapsular una referencia cuando sea necesario. Deberías ir por el bolígrafo (color) por supuesto.

+0

+1 para "¿por qué las personas crean pinceles para crear bolígrafos?" –

+0

Gracias. En su ejemplo a, cepillo b se eliminaría tan pronto como se devuelva la pluma, ¿verdad? Si Pen tuviera una referencia al cepillo b adentro, ¿arrojaría un ejemplo? Sólo me preguntaba. –

+0

Gracias por el ejemplo extendido. –

0

Cuando un método entrega una instancia IDisposable, está entregando simultáneamente la responsabilidad de gestión de por vida.

Ahora es responsabilidad del que llama deshacerse del objeto después de su uso. Si ese objeto contiene otros objetos IDisposable, por convención, debemos esperar que el contenedor para disponer adecuadamente de sus hijos cuando lo disponga - de lo contrario implicaría un error en el contenedor.

En su ejemplo concreto, debe esperar que el Pen elimine su instancia interna de Brush cuando la deseche.

+0

¿Los colores son desechables también? –

+1

No, Color es una estructura. – Groo

+1

@Joan Venge: 'Error' - Lo corregí al mismo tiempo que tu comentario ... –

2

Su problema no tiene una solución general.

En el ejemplo específico, no es un problema, porque la pluma tiene un constructor que toma un color directamente.

Algunas clases se desharán de sus propios parámetros de constructor (especialmente clases relacionadas con Stream); revisa cada clase en Reflector.

Si la clase está volviendo hereda de Component, se podría agregar un controlador para su evento de De baja.

Si la clase está volviendo no está sellado, se puede crear una versión heredada que dispone el objeto que lo creó a partir también.

Por último, si realmente quisiera, podría crear una clase de contenedor que contiene el objeto que se está volviendo y dispone el parámetro constructor. Sin embargo, eso sería muy confuso y no lo recomendaría.

+0

Gracias, no sabía que Pen podría tomar un Color directamente. Es divertido porque veo un montón de código creando el pincel y el bolígrafo por separado y luego simplemente usando el Pen para pintar. –

+0

Entonces debes aceptar esta respuesta. – SLaks

+0

Sí, lo hace. Simplemente no hay una solución general limpia para ello. – SLaks

1

Una de mis fuese con muchas de las clases relacionadas con los gráficos es que no hay un patrón consistente para el manejo de estos temas. Lo que realmente se necesita es un medio para implementar el conteo parcial de referencias. No en el estilo COM, donde el hecho de pasar referencias requiere un constante repunte de los recuentos de referencia, pero en un medio por el cual, dado un objeto gráfico IDisposable, se puede solicitar otra instancia que comparta el mismo recurso subyacente. Los recursos mismos se encapsularían en un objeto compartido con un contador de referencia. Crear otra instancia de referencia incrementaría el contador; Llamar a Dispose en una instancia de referencia lo disminuiría. Esto evitaría el 95% de la sobrecarga del recuento de referencias, mientras que conserva el 99% del beneficio.

Cuestiones relacionadas