Как удалить (отменить регистрацию) зарегистрированный экземпляр из сопоставления Unity? - PullRequest
34 голосов
/ 24 апреля 2010

Я столкнулся с одной проблемой, которую сейчас не могу решить. У меня есть следующее:

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

где UnityHelper.DefaultContainer - мой помощник для получения контейнера Unity с загруженной конфигурацией.

здесь я зарегистрировал instance как экземпляр IMyInterface.

Так что где угодно (через некоторое время после использования) я хочу удалить это отображение. Удали это вообще. Как я могу это сделать?

Я пытался:

UnityHelper.DefaultContainer.Teardown(instance)

, но это не удалось, и следующий код все равно возвращает instance:

UnityHelper.DefaultContainer.ResolveAll<IMyInterface>()

Ответы [ 6 ]

27 голосов
/ 21 июня 2013

У меня была такая же проблема, и я просто удалил регистрацию ContainerControlledLifetimeManager из моего Container:

foreach (var registration in container.Registrations
    .Where(p => p.RegisteredType == typeof(object)
                && p.Name == name
                && p.LifetimeManager.Type == typeof(ContainerControlledLifetimeManager)))
{
    registration.LifetimeManager.RemoveValue();
}
11 голосов
/ 25 апреля 2010

Я думаю, это то, что вы ищете.

var lifetimeManager = new TransientLifetimeManager();
UnityHelper.DefaultContainer.RegisterInstance(typeof(IMyInterface), "test", instance, lifetimeManager);
lifetimeManager.RemoveValue();
9 голосов
/ 08 марта 2011

Вот как я обработал незарегистрированные экземпляры из контейнера Unity

Мне нужно было реализовать функцию добавления / удаления, например:

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

Я создал собственный менеджер времени жизни для выполнения

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;
    }
}

Вот окончательная реализация:

    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);
    }

вызов removevalue в пользовательском менеджере времени жизни приводит к тому, что экземпляр становится незарегистрированным

6 голосов
/ 30 марта 2017

Это старый вопрос, но некоторые ответы вводят в заблуждение, поэтому я приведу свой собственный. Вы не можете сделать это с Unity. Конец истории. Вызов RemoveValue для менеджеров продолжительности жизни при регистрации не приводит к отмене регистрации ( больше информации о пожизненных менеджерах ), и этот метод не предназначен для отмены регистрации чего-либо. Таким образом, окончательное поведение является неожиданным и не удобным. Конечно, RemoveValue имеет еще меньше смысла, если вы регистрируете реализацию или фабричный метод, хотя вопрос заключается в отмене регистрации экземпляров. Рассмотрим следующий фрагмент кода

    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();
        }
    }

Если вы отладите его, вы увидите, что после вызова ClearValue контейнер все еще говорит, что он зарегистрирован, но если вы попытаетесь разрешить этот экземпляр, он выдаст исключение. Что еще хуже, звонки на ResolveAll<T> тоже не удастся.

Подводя итог, независимо от того, выполняете ли вы ClearValue, оборачиваете свой экземпляр регистра другим IoC или пользовательским классом или предоставляете свой собственный LifeTimeManager, ResolveAll<T> и IsRegistered<T> не будут вести себя должным образом, и регистрация все еще будет там. Так что не пытайтесь, потому что это не сработает, и это вызовет проблемы в будущем.

3 голосов
/ 13 ноября 2012

У меня та же проблема, и после эксперимента я решил ее, используя стандартный ContainerControlledLifetimeManager и вызывая RemoveValue, когда я хочу удалить экземпляр контейнера. Обратите внимание, что если вы не используете интерфейсы и у вашего объекта есть конструктор, который контейнер может найти и использовать, он будет воссоздавать экземпляр после того, как вы уничтожили его с помощью lifeManager.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; }
    }
}
1 голос
/ 01 мая 2010

У меня было похожее требование, согласно которому я хотел временно хранить объекты в контейнере для единства и обнаружил, что это невозможно (или, по крайней мере, легко возможно). Если ваша цель состоит в том, чтобы обеспечить временное хранилище, легко доступное для Unity, то создайте службу временного хранения.

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;
    }
}

Зарегистрируйте свой сервис в Unity. Затем, когда вы хотите сохранить объект, вы вызываете метод Deposit, а когда вы хотите удалить объект, вы вызываете метод Withdraw. Более полное объяснение можно найти здесь

...