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
- Comment créer des variables avec des noms dynamics en C #?
- Accessibilité incohérente: le type de champ ‘TagHandler’ est moins accessible que le champ ‘EditTag.tag’
- Comment modifier le contenu de la boîte de dialog MahApps.Metro à l’aide de styles (remix)
- IndexOutofRangeException: Il n’y a pas de ligne en position 0
- Accessibilité incohérente: type de propriété
Dans le code ci-dessous (simplifié), _Baz
et _Bar
implémentent IDisposable .
Donc les questions sont,
[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); } }