Question

J'ai un singleton qui utilise "l'instance T statique en lecture seule = new T ();"; modèle. Cependant, j'ai rencontré un cas où T est jetable et doit en fait être éliminé pour les tests unitaires. Comment puis-je modifier ce modèle pour prendre en charge un singleton jetable?

L'interface que je voudrais ressembler à quelque chose comme:

var x = Foo.Instance;
var y = Foo.Instance; // x == y
...
x.Release(); // this causes the next Foo.Instance to return a fresh object
             // also, it assumes no further operations on x/y will be performed.

Remarque - le motif doit évidemment être thread-safe.

Modifier : aux fins du code de production, il s'agit d'un véritable singleton. Le problème, c’est que certains fichiers sont verrouillés. Par conséquent, pour le nettoyage des tests unitaires, nous devons le supprimer.

Je préférerais également un motif pouvant être réutilisé, si possible.

Était-ce utile?

La solution

Marquez Release en tant que internal et utilisez l'attribut InternalsVisibleTo pour l'exposer uniquement à votre assembly de test unitaire. Vous pouvez le faire ou si vous vous méfiez de quelqu'un dans votre assemblée l'appellera, vous pouvez le marquer comme privé et y accéder en utilisant la réflexion.

Utilisez un finaliseur dans votre singleton qui appelle la méthode Dispose sur l'instance de singleton.

Dans le code de production, seul le déchargement d'un AppDomain entraîne l'élimination du singleton. Dans le code de test, vous pouvez appeler vous-même Valider .

Autres conseils

À ce stade, je ne pense pas que je considérerais vraiment cela comme un singleton, pour être honnête.

En particulier, si un client utilise un singleton, il ne s’attendra vraiment pas à ce qu’il doive en disposer, et il serait surpris que quelqu'un d'autre l'utilise.

Que va faire votre code de production?

EDIT: Si vous avez vraiment vraiment besoin de ceci pour les tests unitaires et seulement pour les tests unitaires (ce qui peut paraître discutable en termes de conception, pour être franc), vous pouvez toujours jouer avec le champ en utilisant la réflexion. . Il serait plus judicieux de déterminer s’il s’agit vraiment d’être un singleton ou si cela devrait vraiment être jetable - les deux vont très rarement ensemble.

Les singletons ne doivent pas être jetables. Période. Si quelqu'un appelle Dispose prématurément, votre application est vissée jusqu'à ce qu'elle redémarre.

 public class Foo : IDisposable
  { [ThreadStatic] static Foo _instance = null;

    private Foo() {IsReleased = false;}

    public static Foo Instance
     { get
        { if (_instance == null) _instance = new Foo();
          return _instance;
        }
     }

    public void Release()
     { IsReleased = true;
       Foo._instance = null;
     }

    void IDisposable.Dispose() { Release(); }

    public bool IsReleased { get; private set;}

  }

Si la classe implémente IDisposable (comme vous le supposez), appelez simplement x.Dispose ()

Vous pouvez utiliser un singleton paresseux imbriqué (voir ici ) avec certains modifications simples:

public sealed class Singleton : IDisposable
{
    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (!Nested.released)
                return Nested.instance;
            else
                throw new ObjectDisposedException();
        }
    }

    public void Dispose()
    {
         disposed = true;
         // Do release stuff here
    }

    private bool disposed = false;

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
}

N'oubliez pas de lancer ObjectDisposedException dans toutes les méthodes / propriétés publiques de l'objet s'il a été supprimé.

Vous devriez également fournir une méthode de finalisation pour l'objet, au cas où Dispose ne serait pas appelé. Découvrez comment mettre correctement en œuvre IDisposable ici .

Pour les tests unitaires, vous pouvez utiliser un " manuel " exemple (mais vous auriez besoin d’un moyen d’instancier l’objet).

Dans votre cas, vous devriez probablement mieux utiliser le modèle d'usine (abstract / method - celui qui vous convient le mieux), associé à un singleton.

Si vous souhaitez vérifier si le singleton a correctement éliminé les objets utilisés (dans le test unitaire), utilisez la méthode Factory, sinon utilisez le modèle singleton.

Soit dit en passant, si vous n’avez pas accès au code source du singleton ou si vous n’êtes pas autorisé à le modifier, vous feriez mieux de l’envelopper dans un autre singleton, et de fournir toute la logique du nouveau (plus Procuration). Cela semble excessif, mais cela pourrait être une solution viable.

Pour pouvoir en contrôler l'accès, fournissez une fabrique et laissez les clients récupérer le nouvel objet uniquement si celui-ci n'a pas été supprimé.

Une autre option pour créer un Singleton jetable consiste à utiliser l'attribut [Singleton] de SandCastle pour votre classe. Le framework Castle se chargera ensuite de disposer de tous les objets Singleton jetables

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top