Passer un object IDisposable par référence provoque une erreur?

J’essaie de créer une méthode générale pour disposer d’un object qui implémente IDisposable , appelé DisposeObject()

Pour être sûr de disposer d’un object pointé par référence d’origine, j’essaie de transmettre un object par référence.

Mais je reçois une erreur de compilation qui dit

Le type d’argument ‘ref’ ne correspond pas au type de paramètre

Dans le code ci-dessous (simplifié), _Baz et _Bar implémentent IDisposable .

texte alternatif

Donc les questions sont,

  1. Pourquoi est-ce que je reçois cette erreur?
  2. Y a-t-il un moyen de le contourner?

[MISE À JOUR] Depuis les réponses fournies jusqu’à présent, tant que je ne mets pas un argument identifiable à null, je peux simplement passer un object par valeur sans utiliser ref . J’ai maintenant un autre problème pour définir des objects jetables sur null ou non dans la méthode DisposeObject .

Voici la source complète pour la complétude:

 public class Foo : IDisposable { private Bar _Bar; private Baz _Baz; private bool _IsDisposed; ~Foo() { Dispose(false); } public void Dispose(bool disposing) { if (!_IsDisposed) { if (disposing) { DisposeObject(ref _Baz); DisposeObject(ref _Bar); } } _IsDisposed = true; } private void DisposeObject(ref IDisposable obj) { try { if (obj == null) return; obj.Dispose(); obj = null; } catch (ObjectDisposedException) { /* Already Disposed... */ } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } public class Bar : IDisposable { public void Dispose() {} } public class Baz : IDisposable { public void Dispose() {} } 

[RÉSULTAT]
J’ai supprimé le code qui définit l’argument sur null ( obj = null; ) dans DisposeObject . Le code final est donc devenu.

  public void Dispose(bool disposing) { if (!_IsDisposed) { if (disposing) { DisposeObject(_Baz); DisposeObject(_Bar); } } _IsDisposed = true; } private void DisposeObject(IDisposable obj) { try { if (obj == null) return; obj.Dispose(); } catch (ObjectDisposedException) { /* Already Disposed... */ } } 

Vous n’avez pas besoin de passer par référence, car vous passez un type de référence. Vous devez supprimer le mot clé ref de la définition de votre méthode. Faites ceci et vous ne devriez pas avoir de problèmes, bien que je ne sois pas sûr de savoir si cela est plus efficace ou plus clair que d’appeler simplement Dispose() (à part le fait que vous n’avez pas à le lancer pour des implémentations explicites, ce qui un chèque null pour vous).

modifier

Danse, bien que j’espère que la discussion entourant ce sujet vous a été utile, votre intention initiale ne semble pas être une chose faisable. Pour passer quelque chose en tant que ref , vous ne pouvez pas transmettre une variable dont le type est différent de celui ref paramètre ref (autrement dit, vous ne pouvez pas transmettre une variable déclarée en tant que class ou autre interface implémentant IDisposable si le paramètre ref paramètre ref est IDisposable ). Étant donné que les parameters ref autorisent la propagation des assignations à l’appelant, vous pouvez autoriser le stockage de types incompatibles dans votre variable.

Votre meilleur pari ici est d’affecter la valeur null si vous le souhaitez. Si vous souhaitez encapsuler la vérification de null et ignorer les exceptions dans la fonction, cela ne va pas, mais la ref ne fonctionnera pas pour vous dans ce scénario, quelle que soit la façon dont vous la découpez, malheureusement.

Voici une option pour votre exemple (vous ne pouvez pas le comparer à un compilateur pour le moment, mais vous aurez l’idée):

 private void DisposeObject(ref T obj) where T : IDisposable { // same implementation } 

Pour l’appeler, utilisez

 DisposeObject(ref _Baz); DisposeObject(ref _Bar); 

Comme indiqué dans les autres commentaires, l’erreur de compilation que vous obtenez a son propre objective (vous empêcher d’affecter un autre type d’IDisposable dans votre méthode, ce qui entraînerait un état incohérent).

Essaye ça:

 IDisposable d = (IDisposable)_Baz; DisposeObject(ref d); 

Edit : Comme Adam le fait remarquer, votre code ne nécessite pas que cela soit ref. Les objects sont toujours passés en tant que références.

Cette approche sent drôle, mais je l’ignorerai pour le moment.

Pour résoudre votre problème, vous devez convertir les objects que vous transmettez avec “(IDisposable)”

Je concède à la volonté du compilateur, et Jon Skeet. Vous avez besoin d’un object réel pour cela:

 IDisposable _BazD = (IDisposable)_Baz; DisposeObject(ref _BazD); 

J’appendais également une vérification nulle dans votre DisposeObject () en plus de try / catch. L’object “obj == null” constituera une vérification simple et rapide par rapport à la capture d’exceptions coûteuse si elle devait être touchée plusieurs fois pour le même object. Hmm … c’était là il y a une minute? Ça ne fait rien.

Merci Dan C. Je n’ai pas encore assez de reps pour append des commentaires, je dois donc append ceci comme réponse. Cependant, cette solution mérite l’attention de Dan C.

C’est un code de travail:

 public override void Dispose() { base.Dispose(); DisposeOf(ref userAdapter); DisposeOf(ref productsAdapter); if (connection != null) { if (connection.State == ConnectionState.Open) { connection.Close(); } DisposeOf(ref connection); } } private void DisposeOf(ref T objectToDispose) where T : IDisposable { if (objectToDispose != null) { objectToDispose.Dispose(); objectToDispose = default(T); } }