2015-08-26 1 views
5

Dans quelques endroits, les gens ont suggéré d'utiliser private void Dispose(bool) pour le modèle IDisposable. Cela semble obsolète (du moins pour les classes non scellées), car le nouveau modèle suggéré (selon Microsoft) est protected virtual void Dispose(bool). Le fait est que l'analyse de code ne signale pas private void Dispose(bool) pour avoir violé CA1063, même s'il semble violer le modèle directement.private void Dispose (bool)?

Quoi de neuf? ? Est-ce private void Dispose(bool) s'en quelque sorte appelé (ou compilé à quelque chose qui ressemble à protected virtual Dispose(bool)

Si cela est une question avec l'analyse du code et le schéma incorrect, sont là des façons de détecter ce Peut-être avec StyleCop

Modifier?: après mûre réflexion, est-ce qu'une classe de base peut appeler base.Dispose() qui a frappé private void Dispose(bool) Même si elle ne peut pas passer un argument

Edit:? Exemple

public class A : IDisposable 
{ 
    ~A() 
    { 
     this.Dispose(false); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private void Dispose(bool disposing) // Should be protected virtual void Dispose(bool) 
    { 
     Console.WriteLine("A"); 
    } 
} 

public class B : A 
{ 
    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     Console.WriteLine("B"); 
    } 
} 

public static class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     a.Dispose(); // Prints "A" 

     B b = new B(); 
     b.Dispose(); // Prints "A"! 
    } 
} 

Comme vous pouvez le voir, cela rend l'utilisation du modèle de disposition totalement difficile.

Vous pouvez contourner cela un peu en cachant le public void Dispose(void) puis en appelant le base.Dispose() quelque part. Cela fonctionne alors "similaire" à la disposition appropriée lors de l'appel B b = new B(); b.dispose();sauf lors de l'appel A b = new B(); b.Dispose();, qui appelle seulement la méthode A.

public class B : A 
{ 
    public void Dispose() // Causes CA error with or without "new". 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     base.Dispose(); // Writes "A" (without quotes). 
     Console.WriteLine("B"); 
    } 
} 

Fondamentalement, tout cela semble terrible. Savons-nous s'il s'agit d'un bug que CA accepte private void Dispose(bool) et y a-t-il un moyen de lancer au moins un avertissement avec StyleCop? Editer: Je ne pense pas que je devrais accepter la réponse d'Alexandre, par rapport à la question que je me pose, il se résume à "Peut-être un bug", avec quelque chose qui devrait être un commentaire. Si quelqu'un d'autre a quelque chose de plus concluant, je pense que ce serait une réponse plus appropriée.

+0

Qu'en est-il des classes scellées? Protégé devrait être utilisé pour les classes ouvertes, privé pour scellé. –

+0

Cela fonctionne pour l'un ou l'autre est le problème. Nous avons trouvé quelques endroits où les classes non scellées ne jetaient pas le problème. Cela a du sens cependant, que privé est requis pour les classes scellées. Pourtant, il serait bon que CA lance si la classe est descellée (et elle devrait le savoir aussi). Je pense que mon montage montre pourquoi il n'est peut-être pas complètement sorti des bois pour qu'il ne jette pas, mais c'est quand même un peu énervant. –

+0

L'appel 'base.Dispose()' serait une violation claire du modèle, donc je ne pense pas qu'il l'explique. Je suis d'accord avec votre pensée originale que l'analyse de code devrait rapporter le cas que vous avez présenté. – sstan

Répondre

6

Implementing a Dispose Method

Le IDisposable Interface nécessite la mise en œuvre d'un seul méthode parameterless, Dispose. Cependant, le motif de Éliminez nécessitedeux méthodes Dispose à appliquer:

  • Un non virtuel public (noninheritable dans Visual Basic) IDisposable.Dispose mise en œuvre qui n'a pas de paramètres.
  • Une méthode virtuelle protégée (Overridable dans Visual Basic) Dispose.

Parce que le public (noninheritable dans Visual Basic) non virtuel, parameterless méthode Dispose est appelé par un consommateur du type, son but est de libérer des ressources non gérés et d'indiquer que le finaliseur, si on est présent, n'a pas à courir. En raison de cela, il a une implémentation standard:

public void Dispose() 
{ 
    // Dispose of unmanaged resources. 
    Dispose (true); 
    // Suppress finalization. 
    GC.SuppressFinalize (this); 
} 

Dans la deuxième surcharge, le paramètre cédante est un booléen qui indique si l'appel de méthode vient d'une méthode Dispose (sa valeur est true) ou d'un finalizer (sa valeur est false).

Lorsque le garbage collector décide que votre objet n'est plus nécessaire, il va essayer de le finaliser dans le cas où vous avez oublié d'appeler la méthode Éliminez parameterless, parce que si vous avez fait et vous suivez le modèle, l'appel serait supprimé.

Voir: How Finalization Works

privé vs protégé virtuel:

Vous devez toujours utiliser la protection virtuelle que la documentation indique si jamais vous voulez soutenir les sous-classes qui suit le modèle correctement.

Pourquoi certaines personnes utilisent la version privée? Peut-être parce que l'héritage n'a jamais été leur intention, surtout si vous générez des méthodes à la volée en utilisant des outils comme Resharper, la plupart du temps ces méthodes vont être privées. Pourquoi l'analyse de code ne signale-t-elle pas le problème?

Peut être un bug. Fournissez un petit échantillon qui donne le problème afin que d'autres personnes puissent tester sur leurs machines.

+0

Ajouter ed quelques échantillons. –

+0

Quel différent Dispose (bool) devrait faire quand le bool est vrai et faux? – AksharRoop

+0

À la fin de la page (https://msdn.microsoft.com/fr-fr/library/system.object.finalize.aspx), vous verrez un exemple. Si la valeur est true, vous devez disposer de toutes les ressources, car vous appelé la méthode de disposer et de récupérer toute la mémoire utilisée. Si faux, cela signifie que le garbage collector est en train de supprimer l'objet, alors vous devez seulement disposer des ressources non managées (objets créés en dehors de votre application C#), le reste des objets peut être laissé intact car le garbage collector supprimera eux quand il le faut. –