web-dev-qa-db-fra.com

Comment supprimer (Unregister) instance enregistrée de la cartographie de l'unité?

Je rencontre un problème que je ne peux pas résoudre maintenant. J'ai ce qui suit:

UnityHelper.DefaultContainer.RegisterInstance(typeof(IMyInterface), "test", instance);

UnityHelper.DefaultContainer est mon assistant pour obtenir un conteneur d'unité avec une configuration chargée.

ici, j'ai inscrit instance comme une instance de IMyInterface.

Donc, n'importe où (quelque temps après avoir utilisé), je veux supprimer cette cartographie. Enlevez-le du tout. Comment je peux le faire?

J'ai essayé:

UnityHelper.DefaultContainer.Teardown(instance)

mais est échoué et le code suivant renvoie instance de toute façon:

UnityHelper.DefaultContainer.ResolveAll<IMyInterface>()
34
bug0r

Je pense que c'est ce que vous recherchez.

var lifetimeManager = new TransientLifetimeManager();
UnityHelper.DefaultContainer.RegisterInstance(typeof(IMyInterface), "test", instance, lifetimeManager);
lifetimeManager.RemoveValue();
11
er-v

Voici comment j'ai manipulé des instances d'enregistrement d'un conteneur unity

Je devais mettre en œuvre une fonctionnalité Ajouter/Supprimer comme ceci:

public interface IObjectBuilder
{
    void AddInstance<T>(T instance);
    void RemoveInstance<T>(T instance);
}

J'ai créé un gestionnaire de vie personnalisé pour effectuer la mise en œuvre

public class ExplicitLifetimeManager :
    LifetimeManager
{
    object Value;

    public override object GetValue()
    {
        return Value;
    }

    public override void SetValue(object newValue)
    {
        Value = newValue;
    }

    public override void RemoveValue()
    {
        Value = null;
    }
}

Voici la mise en œuvre finale:

    Dictionary<object, ExplicitLifetimeManager> Instances = new Dictionary<object, ExplicitLifetimeManager>();

    public void AddInstance<T>(T instance)
    {
        ExplicitLifetimeManager e = new ExplicitLifetimeManager();
        Instances[instance] = e;
        Container.RegisterInstance(instance, e);
    }

    public void RemoveInstance<T>(T instance)
    {
        Instances[instance].RemoveValue();
        Instances.Remove(instance);
    }

appeler supprimerValue sur le gestionnaire de vie personnalisé provoque l'inscrit d'instance non enregistrée.

9
Brad

C'est une vieille question, mais certaines réponses sont trompeuses, alors je vais fournir le mien. Vous ne pouvez pas faire cela avec l'unité. Fin de l'histoire. Calling RemoveValue sur les inscriptions Les gestionnaires à vie ne réalisent pas de non-administration ( plus d'informations sur les gestionnaires de vie ), et cette méthode n'est pas destinée à désenregistrer quoi que ce soit. Donc, le comportement final est inattendu et n'est pas pratique. Bien sûr, RemoveValue a encore moins de sens si vous enregistrez une mise en œuvre ou une méthode d'usine, bien que la question concerne les instances sans enregistrement. Considérez la prochaine pièce de code

    public interface SomeInterface
    {
        int Foo { get; set; }
    }

    public class SomeImplementation: SomeInterface
    {
        public int Foo { get; set; }
    }

    static void Main(string[] args)
    {
        UnityContainer iocContainer = new UnityContainer();
        string registerName = "instance";
        //before any registration
        Resolve<SomeInterface>(iocContainer, registerName);

        iocContainer.RegisterInstance<SomeInterface>(registerName, new SomeImplementation());

        //after registration
        Resolve<SomeInterface>(iocContainer, registerName);

        ClearValue<SomeInterface>(iocContainer, registerName);

        //after clear value
        Resolve<SomeInterface>(iocContainer, registerName);


    }

    private static void Resolve<T>(UnityContainer iocContainer,string name)
    {
        if (iocContainer.IsRegistered<T>(name))
            iocContainer.Resolve<T>(name);

        iocContainer.ResolveAll<T>();
    }
    private static void ClearValue<T>(UnityContainer iocContainer, string name)
    {
        foreach (var registration in iocContainer.Registrations.Where(p => p.RegisteredType == typeof(T)
            && p.Name==name))
        {
            registration.LifetimeManager.RemoveValue();
        }
    }

Si vous le débogez, vous verrez qu'après l'appel à ClearValue, le conteneur dit toujours qu'il est enregistré, mais si vous essayez de résoudre ce cas, il lancera une exception. Qu'est-ce qui est encore pire, appelle à ResolveAll<T> va échouer aussi.

Pour résumer, peu importe si vous le faites ClearValue, enveloppez votre instance de registre avec une autre COI ou une classe personnalisée, ou fournissez votre propre vie à LifeMemanager, ResolveAll<T> et IsRegistered<T> ne se comportera pas comme prévu et l'inscription sera toujours là. Alors n'essayez pas parce que cela ne fonctionnera pas et cela causera des problèmes sur la route.

6
Muscicapa Striata

J'ai le même défi et après avoir expérimenté, je l'ai résolu à l'aide de la standard ContainControlledlifeMeMeManager et appelez SuveValue lorsque je souhaite supprimer l'instance de conteneur. Notez que si vous n'utilisez pas d'interfaces et que votre objet a un constructeur que le conteneur peut trouver et utiliser, il recréera l'instance après l'avoir détruit avec LifeMemanager.RemoveValue ().

[TestClass]
public class UnityContainerTest
{
    [TestMethod]
    public void RemoveFromContainer()
    {
        UnityContainer container = new UnityContainer();
        MyUnityMember member = new MyUnityMember(5);

        LifetimeManager lifetimeManager = new ContainerControlledLifetimeManager();
        container.RegisterInstance(member, lifetimeManager);

        var resolved = container.Resolve<MyUnityMember>();
        Assert.IsNotNull(resolved);

        lifetimeManager.RemoveValue();

        try
        {
            resolved = container.Resolve<MyUnityMember>();
            Assert.Fail(resolved + " is still in the container");
        }
        catch (ResolutionFailedException)
        {
        }
    }

    public class MyUnityMember
    {
        public MyUnityMember(int x)
        {
            I = x;
        }

        public int I { get; private set; }
    }
}
3
Velimir

J'ai eu une exigence similaire dans laquelle je voulais stocker temporairement des objets dans le conteneur d'unité et que cela n'était pas possible (ou du moins facilement possible). Si votre objectif est d'avoir un lieu de stockage temporaire facilement accessible à l'unité, créez un service de stockage temporaire.

public class TemporaryStorageService : ITemporaryStorageService
{
    public void Deposit<T>(Object o, string key)
    {
        System.Windows.Application.Current.Properties[key] = o;
    }

    public T Withdraw<T>(string key)
    {   T o = (T)System.Windows.Application.Current.Properties[key];
        System.Windows.Application.Current.Properties.Remove(key);
        return o;
    }
}

Enregistrez votre service avec Unity. Ensuite, lorsque vous souhaitez stocker un objet, vous appelez la méthode de dépôt et lorsque vous souhaitez supprimer l'objet, vous appelez la méthode de retrait. Une explication plus complète peut être trouvée ici

1
Allan