如何从Unity映射中删除(取消注册)已注册的实例?

时间:2010-04-24 17:20:50

标签: c# unity-container ioc-container instance registering

我遇到了一个我现在无法解决的问题。 我有以下内容:

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

其中UnityHelper.DefaultContainer是我的帮助器,用于获取带有加载配置的统一容器。

此处我将instance注册为IMyInterface的实例。

所以在任何地方(使用后一段时间)我想删除此映射。完全删除它。我怎么能这样做?

我试过了:

UnityHelper.DefaultContainer.Teardown(instance)

但是不成功,以下代码仍然返回instance

UnityHelper.DefaultContainer.ResolveAll<IMyInterface>()

6 个答案:

答案 0 :(得分:27)

我遇到了同样的问题,只是从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();
}

答案 1 :(得分:11)

我认为这就是你要找的东西。

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

答案 2 :(得分:9)

以下是我如何处理来自统一容器的取消注册实例

我需要实现这样的添加/删除功能:

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会导致实例未注册

答案 3 :(得分:6)

这是一个老问题,但有些答案会产生误导,所以我会提供自己的答案。 你不能用Unity做到这一点。故事的结局。 在注册生命周期管理器上调用RemoveValue无法实现取消注册(more information about lifetime managers),并且该方法不用于取消注册任何内容。所以最后的行为是意外的,不方便。当然,如果您注册实现或工厂方法,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> won' t表现如预期,注册仍然存在。因此,不要尝试它,因为它不会起作用,它将导致问题。

答案 4 :(得分:3)

我遇到了同样的挑战,经过实验后,我通过使用标准的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 :(得分:1)

我有一个类似的要求,我想暂时将对象存储在统一容器中,发现这是不可能的(或者至少很容易)。 如果您的目标是让一个临时存储位置易于统一,那么就创建一个临时存储服务。

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方法。 更全面的解释可以是found here