Подтвердить что ты не робот

Как удалить (отменить регистрацию) зарегистрированный экземпляр из Unity mapping

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

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

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

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

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

Я пробовал:

UnityHelper.DefaultContainer.Teardown(instance)

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

UnityHelper.DefaultContainer.ResolveAll<IMyInterface>()
4b9b3361

Ответ 1

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

foreach (var registration in container.Registrations
    .Where(p => p.RegisteredType == typeof(object)
                && p.LifetimeManagerType == typeof(ContainerControlledLifetimeManager)))
{
    registration.LifetimeManager.RemoveValue();
}

Ответ 2

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

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

Ответ 3

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

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

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 в пользовательском менеджере времени жизни заставляет экземпляр незарегистрироваться

Ответ 4

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

Ответ 5

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

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. Затем, когда вы хотите сохранить объект, вы вызываете метод депозита, и когда вы хотите удалить объект, который вы вызываете методом Withdraw. Более полное объяснение может быть найдено здесь

Ответ 6

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

    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> не будете вести себя так, как ожидалось, и регистрация все равно будет. Поэтому не пытайтесь, потому что это не будет работать, и это вызовет проблемы в будущем.