web-dev-qa-db-ja.com

Unityマッピングから登録済みインスタンスを削除(登録解除)する方法は?

今は解決できない問題に出会います。私は以下を持っています:

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

どこ UnityHelper.DefaultContainerは、ロードされた構成で単一のコンテナーを取得するための私のヘルパーです。

ここでは、instanceIMyInterfaceのインスタンスとして登録しました。

だからどこでも(使用後しばらくして)このマッピングを削除したいです。完全に削除します。どうすればできますか?

私が試してみました:

UnityHelper.DefaultContainer.Teardown(instance)

しかし、これは失敗し、次のコードはとにかくinstanceを返します。

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

同じ問題が発生し、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();
}
28
Johannes Wanzek

それがあなたが探しているものだと思います。

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

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を呼び出すと、インスタンスが登録解除されます

9
Brad

これは古い質問ですが、いくつかの答えは誤解を招くので、私は自分の質問を提供します。 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>は動作しません予想通り、登録はまだあります。機能しないので試してはいけません。問題が発生する可能性があります。

6

同じ問題があり、実験した後、標準の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; }
    }
}
3
Velimir

同様の要件で、オブジェクトをユニティコンテナーに一時的に格納する必要があり、これは不可能である(または少なくとも簡単に可能である)ことがわかりました。一時保管場所を簡単に利用できるようにすることが目的の場合は、一時保管サービスを作成します。

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メソッドを呼び出します。より詳しい説明は ここにあります

1
Allan