2009-10-08 12 views
7

Si vous avez une brosse et un stylo comme dans:Comment manipuler des objets jetables auxquels nous n'avons pas de référence?

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

et les disposer comme ceci:

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

Comment voulez-vous éliminer si elle était:

Pen p = CreatePenFromColor(color) qui créeraient la brosse et stylo pour vous? Je ne peux pas jeter le pinceau dans cette méthode, n'est-ce pas?

Est-ce une méthode à ne pas utiliser avec des objets jetables?

EDIT: Qu'est-ce que je veux dire, comment disposez-vous la brosse?

+0

o.O Je ne savais pas que Brush and Pen implémentait IDisposable ... –

+0

lol, c'est certainement le cas. –

+0

Mais où est ce pinceau référencé? Pourquoi (et où) le créez-vous si vous renvoyez seulement un stylo comme résultat de la méthode? – Groo

Répondre

9

La méthode CreatePenFromColor a pour rôle de disposer de l'instance Brush.Ce n'est pas évident d'un coup d'œil, mais si vous creusez dans l'implémentation de la classe Pen, vous verrez qu'elle ne tient pas sur l'instance Brush. Au lieu de cela, il l'utilise simplement pour calculer quelques valeurs. Il n'y a donc aucune raison pour que l'instance Brush vive au-delà de l'appel à CreatePenFromColor et que la méthode doit disposer de l'instance.

+0

Merci Jared, je ne le savais pas. –

+0

Ce n'est pas nécessairement vrai. le constructeur de Pen passe le handle du pinceau à 'GdipCreatePen2'. Je ne sais pas si 'GdipCreatePen2' a besoin de la brosse pour rester en vie (la fonction est à peine documentée), mais je suppose que c'est le cas.Souvenez-vous que le pinceau pourrait être un 'TextureBrush' avec une image, et vous ne voudriez pas que le Pen fasse une copie séparée de l'image en mémoire pour que vous puissiez disposer du pinceau. – SLaks

+1

@Slaks, GdipCreatePen2 AFAIK n'en a pas besoin pour rester en vie. J'ai creusé à travers la documentation très limitée et c'est seulement nécessaire pour installer le stylo, pas pour le maintenir. – JaredPar

6

Vous devez quand même l'éliminer lorsque vous avez terminé.

Par exemple, vous pouvez l'appeler comme ceci:

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

Si une méthode renvoie un objet IDisposable, il est de votre devoir de le disposer.

[Éditer] Maintenant j'ai eu la question - vous utilisez le constructeur Pen (Brush b).

a. Dans ce cas, il semble que Pen n'a pas besoin de l'instance brosse après le constructeur, de sorte que votre méthode pourrait ressembler à ceci:

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

b. Pourquoi ne pas simplement utiliser Pen(Color color)?

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

c. (en ce qui concerne le commentaire) Si le stylo contient une référence interne au pinceau, vous ne pourrez pas le jeter avant d'avoir fini avec le stylo. Dans ce cas, je pencherais pour une classe qui ferait le travail pour moi:

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

puis l'utiliser comme ceci:

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

Avertissement: IDisposable ne sont pas mis en œuvre conformément aux lignes directrices, mais plutôt pour la démonstration seulement. En outre, l'exemple entier est utilisé uniquement pour montrer comment encapsuler une référence en cas de besoin. Vous devriez aller pour Pen (couleur) bien sûr.

+0

+1 pour "Pourquoi les gens créent-ils des pinceaux pour créer des stylos?!?" –

+0

Merci. Dans votre exemple a, le pinceau b serait éliminé dès que Pen serait retourné, n'est-ce pas? Si Pen avait une référence à brosser b à l'intérieur, alors il donnerait un exemple? Je me demandais juste. –

+0

Merci pour l'exemple étendu. –

0

Lorsqu'une méthode désactive une instance IDisposable, elle transfère simultanément la responsabilité de la gestion de la durée de vie.

Il appartient maintenant à l'appelant de se débarrasser de l'objet après utilisation. Si cet objet contient d'autres objets IDisposable, par convention, nous devons nous attendre à ce que le conteneur dispose correctement de ses enfants lorsque nous le jetterons, sinon cela impliquerait un bogue dans le conteneur.

Dans votre exemple concret, vous devriez vous attendre à ce que le Pen dispose de son instance interne de pinceau lorsque vous le jetez.

+0

Les couleurs sont jetables aussi? –

+1

Non, la couleur est une structure. – Groo

+1

@Joan Venge: 'Typo' - Je l'ai corrigé en même temps que votre commentaire ... –

2

Votre problème n'a pas de solution générale.

Dans votre exemple spécifique, ce n'est pas un problème, car Pen a un constructeur qui prend une couleur directement.

Certaines classes disposent elles-mêmes de leurs paramètres constructeurs (en particulier les classes liées au flux); vérifiez chaque classe dans Reflector.

Si la classe que vous renvoyez hérite de Component, vous pouvez ajouter un gestionnaire à son événement Disposed.

Si la classe que vous renvoyez n'est pas scellée, vous pouvez créer une version héritée qui dispose également de l'objet que vous avez créé. Enfin, si vous le vouliez vraiment, vous pourriez créer une classe wrapper qui contient l'objet que vous renvoyez et élimine le paramètre constructor. Cependant, ce serait très déroutant et je ne le recommanderais pas.

+0

Merci, je ne savais pas que Pen pouvait prendre une couleur directement. C'est drôle parce que je vois beaucoup de code créant la brosse et le stylo séparément et ensuite en utilisant le stylo pour peindre. –

+0

Ensuite, vous devriez accepter cette réponse. – SLaks

+0

Oui, c'est le cas. Il n'y a tout simplement pas de solution générale propre. – SLaks

1

L'une de mes bêtes avec de nombreuses classes liées aux graphiques est qu'il n'y a pas de modèle cohérent pour gérer de tels problèmes. Ce dont on a vraiment besoin, c'est d'un moyen de mise en œuvre du comptage partiel des références. Pas dans le style COM, où le fait de contourner des références nécessite un nombre constant de références, mais dans un moyen par lequel, étant donné un objet graphique IDisposable, on peut demander une autre instance qui partage la même ressource sous-jacente. Les ressources elles-mêmes seraient encapsulées dans un objet partagé avec un compteur de référence. Créer une autre instance de référencement augmenterait le compteur; L'appel de Dispose sur une instance de référencement le décrémenterait. Cela permettrait d'éviter 95% des frais généraux de référence, tout en conservant 99% de l'avantage.