簡體   English   中英

在Unity中的程序集之間共享實例

[英]Sharing instance between assemblies in Unity

目前,我正在使用單例類,並且在我使用它的每個地方都可以。 但是,我想為此使用Unity IoC容器。 按以下方式注冊它不符合我希望的方式:

container.RegisterInstance(new SomeNiceClass(), new ContainerControlledLifetimeManager());

意思是如果我這樣做:

container.Resolve<SomeNiceClass>();

在除了第一次注冊的匯編類中,我將獲得一個新實例。

如您所知,您需要使用相同的容器實例。

您可以通過Unity的IModule接口執行此操作。

[Module(ModuleName="MyExternalModule", OnDemand=false)]
public class MyExternalModule : IModule
{
    private readonly IUnityContainer container;

    public MyExternalModule(IUnityContainer container)
    {
        if (container == null)
            throw new ArgumentNullException("container");

        this.container = container;
    }

    public void Initialize()
    {
        container.RegisterInstance(new MyService());
    }
}

在您的應用程序中,您注冊模塊:

public class ApplicationBootstrapper : UnityBootstrapper
{
    protected override IModuleCatalog CreateModuleCatalog()
    {
        var moduleCatalog = new ModuleCatalog();
        moduleCatalog.AddModule(typeof(YourCompany.MyModule.MyExternalModule), InitializationMode.WhenAvailable);
        return moduleCatalog;
    }
    ...
}

編輯:作為附加說明,您的模塊不應實例化其自己的容器。 容器只需要在主應用程序中實例化即可。 這些模塊僅進行注冊,僅此而已!

如果您需要模塊中容器的實例(在IModule實現之外),則只需在構造函數中聲明它即可。

public class MyModuleResolver 
{
    private readonly IUnityContainer container;

    public MyModuleResolver(IUnityContainer container)
    {
        if(container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }
}

但是,請注意,直接引用您的域/業務層內部的容器不是一個好習慣。 您必須自己親自使用IUnityContainer原因只有兩個:

  1. 在您的引導程序中
  2. 在您的應用程序類型內部,即某些工廠類需要根據運行時參數手動解析某種類型

其他一切都應通過注射從您的容器中自動完成。

只要您將引用傳遞給同一容器,程序集邊界就無關緊要。

您可以嘗試命名:

container.RegisterInstance<SomeNiceClass>("MySingleton", new SomeNiceClass(), new ContainerControlledLifetimeManager());
container.Resolve<SomeNiceClass>("MySingleton");

還值得注意的是,文檔說容器生存期是RegisterInstance的默認值,因此您可以像這樣進行RegisterInstance

container.RegisterInstance<SomeNiceClass>(new SomeNiceClass());

在此處閱讀有關此的MSDN注釋: https : //msdn.microsoft.com/zh-cn/library/ff647854.aspx

如果仍然有問題,則需要再次查看如何處理容器。

我遇到了完全相同的問題(不確定為什么每個人都評論說很難或不可能重現-從我所看到的情況來看很簡單。

僅供參考,以下是重現步驟:

  1. 創建具有2個或更多程序集的解決方案。
  2. 在每個裝配件中放置一個或多個模塊。
  3. 與其加載每個程序集的引導程序硬代碼,不如使用一種動態發現並加載它們的方法。 我使用了一個簡化的版本: http : //brianlagunas.com/prism-dynamically-discover-and-load-modules-at-runtime/
  4. 嘗試在一個模塊中注冊某些單例(ContainerControlledLifetime)類型或實例。
  5. 還要嘗試在其他模塊中引用此單例。
  6. 就我而言,我還按順序在引導程序的ConfigureContainer部分內無序地預加載了第一個“主”模塊-也許這是導致我的問題的一部分。

所有這些就緒后,我重現了相同的問題-Assembly1中的模塊(與主模塊相同)以某種方式獲得了“單人”的實例1,而Assembly2中的模塊(僅稍后以動態方式加載)得到了實例我單身的2。 我確認他們正在使用相同的容器實例。

在我的情況下,我通過將這些單例的注冊完全移出模塊,並在加載任何模塊之前將其移入引導程序(再次在ConfigureContainer中)來解決了這個問題。

還要注意-當我使用Assembly2中的模塊顯式調用ModuleCatalog.AddModule時(無需更改其余代碼),多實例問題就消失了。 但是,當我刪除該調用以顯式加載它(在ConfigureModuleCatalog中),而只允許我的動態模塊目錄動態加載它時,就會出現此問題。 我猜想這一切都是為了在引導程序中按正確的事件順序進行操作-但在這種情況下,它當然無法按您期望的那樣工作。

很抱歉,如果這不是一個非常簡潔的解決方案,那么花了很多時間反復試驗才能解決所有問題。 但我希望這可以對某人有所幫助。

**更新**

經過所有這些寫稿,再仔細考慮……我終於意識到了造成這種情況的原因。 本質上,因為我正在預加載主模塊,該模塊也恰好注冊了一些單例,然后稍后在Bootstrapper模塊初始化階段,Unity隨同其他模塊一起重新加載了該模塊,因此該模塊有效重新注冊這些單例類,我猜這會導致重復的定義,並最終創建另一個實例。 我錯誤地認為Unity足夠聰明,以至於知道它已經加載了模塊,而不是重新加載它。

我在模塊(帶有基本模塊)中添加了一些功能,以僅允許每個模塊加載一次,而忽略了對同一模塊類型(靜態)的任何后續對Initialize的調用。 然后,我將所有單例定義移回了模塊。 現在一切似乎都很好。 所以-這就是我的特殊情況。

因此,請回到最初發布此問題的人員-以及其他任何尋求答案的人-如果您在Unity中多次看到單例實例化,則可能要仔細檢查一下您是否要多次加載模塊或注冊類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM