C# 在Unity中的程序集之间共享实例

C# 在Unity中的程序集之间共享实例,c#,unity-container,C#,Unity Container,目前我正在使用一个singleton类,它在我使用它的每个地方都可以正常工作。不过,我想使用Unity IoC容器来实现这一点。按以下方式注册它与我希望的方式不一样: container.RegisterInstance(new SomeNiceClass(), new ContainerControlledLifetimeManager()); 意思是如果我这样做: container.Resolve<SomeNiceClass>(); container.Resolve();

目前我正在使用一个singleton类,它在我使用它的每个地方都可以正常工作。不过,我想使用Unity IoC容器来实现这一点。按以下方式注册它与我希望的方式不一样:

container.RegisterInstance(new SomeNiceClass(), new ContainerControlledLifetimeManager());
意思是如果我这样做:

container.Resolve<SomeNiceClass>();
container.Resolve();

在程序集中的一个类中(它不是第一次注册的),我将获得一个新实例。

只要您将引用传递给同一个容器,程序集边界就不重要

您可以尝试将其命名为:

container.RegisterInstance<SomeNiceClass>("MySingleton", new SomeNiceClass(), new ContainerControlledLifetimeManager());
container.Resolve<SomeNiceClass>("MySingleton");
请在此处阅读MSDN对此的评论:


如果仍然存在问题,则需要重新审视如何处理容器。

正如您自己所注意到的,您需要使用相同的容器实例

您可以通过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
的原因只有两个:

  • 在你的引导程序里面
  • 在应用程序类型内部,即需要根据运行时参数手动解析特定类型的某些工厂类

  • 其他一切都应该通过注入从容器中自动完成

    我也遇到了同样的问题(不确定为什么每个人都评论说它很难或不可能复制——从我看来,这很简单

    仅供参考,以下是复制的步骤:

  • 创建包含2个或多个程序集的解决方案
  • 在每个组件中放置一个或多个模块
  • 不要让引导程序硬代码加载每个程序集,而是使用一些动态发现和加载它们的方法。我使用了这个的简化版本:
  • 尝试在一个模块中注册一些单例(ContainerControlledLifetime)类型或实例
  • 也尝试在其他模块中引用此单例
  • 在我的例子中,我还按顺序在引导程序的ConfigureContainer部分中预加载了第一个“main”模块——这可能是导致我出现问题的部分原因
  • 一旦所有这些都准备就绪,我就重现了同样的问题——assembly1中的模块(与主模块相同)以某种方式获得了我的“singleton”实例1,而assembly2中的模块(仅在稍后动态加载)获得了我的singleton实例2。我验证了它们使用的是相同的容器实例

    我修复了本例中的问题,在加载任何模块之前,将这些单例的注册完全移出模块,并放入引导程序(再次在ConfigureContainer中)

    另请注意-当我使用assembly2中的模块显式调用ModuleCatalog.AddModule(不更改任何其他代码)时,多实例问题消失了。但当我删除该调用以显式加载它时(在ConfigureModuleCatalog中)相反,我只是允许我的动态模块目录动态加载它,问题就出现了。我想这只是为了在引导程序中按正确的事件顺序进行操作——但在这种情况下,它肯定不会像您预期的那样工作

    抱歉,如果这不是一个非常简洁的解决方案-这需要大量的尝试和错误来解决所有这些问题。但我希望这能帮助一些人

    **更新**

    在写了这么多之后,再仔细考虑一下……我终于意识到是什么导致了这一点。基本上,因为我正在预加载主模块,该模块碰巧也注册了一些单例,然后Unity在引导程序模块init p期间重新加载同一个模块以及所有其他模块实际上,同一个模块正在有效地重新注册那些单例类,我猜这会导致重复的定义,并最终创建另一个实例。我错误地假设Unity在某种程度上足够聪明,知道它已经加载了该模块,而不是重新加载它

    我在我的模块中添加了一些功能(带有一个基本模块),只允许每个模块加载一次,并忽略对同一模块类型进行初始化的任何后续调用(静态).然后我将所有的单例定义移回了模块中。现在一切似乎都很好。所以-这就是我的特殊情况


    因此,回到最初发布这个问题的人——以及其他寻找答案的人——如果您看到您的单例在Unity中被实例化了不止一次,那么可能需要再次检查您是否多次加载模块或注册类型。

    以这种方式从同一容器中注册对象的新实例是非常困难的非常困难(我无法想象你们声称看到的实现结果的方式)。请尝试提供至少与您的设置相似的或代码。我想您误解了我的意思。我的意思是,我不能使用Unity framework共享对象的实例,因为即使我在一个程序集中使用
    RegisterInstance
    ,我在另一个程序集中仍然会得到一个新的实例。我使用单例进行了肮脏的变通。我不喜欢这样解决方案,我更愿意在这个问题上使用Unity。这段代码类似于我的设置-在一个程序集中我正在注册,在另一个程序集中我正在尝试获取实例。我显然误解了你的问题…正如我所说,当调用
    container.Resolve();
    时,我看不到实现你描述的行为的方法
    public class MyModuleResolver 
    {
        private readonly IUnityContainer container;
    
        public MyModuleResolver(IUnityContainer container)
        {
            if(container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }
    }