带有配置文件和单例类的 Unity 框架

发布于 2024-08-14 11:46:35 字数 479 浏览 3 评论 0原文

所以故事是这样的:

我有单例类(又名 ServiceLocator),您可以使用“CreateInstance()”方法获取实例。同时,我们将Unity添加到我们的应用程序中并使用标准配置文件对其进行配置。

当我尝试映射接口 IServiceLocator 以获取 ServiceLocator 实例并将其注册到统一配置文件中时,问题就开始了。 ,ServiceLocator 没有公共构造函数(即单例),因此,当我执行 unity.resolve()... 时,unity 无法创建它。

正如您可能猜到的那样 问题:有没有办法告诉Unity(通过配置文件)使用CreateInstance()而不是尝试执行默认构造函数?如果没有,如果您还有其他想法可以做什么,我将不胜感激。

请不要建议我将构造函数更改为公共,假设我现在无法做到这一点。

So the story goes like this:

I have singleton class (a.k.a ServiceLocator) which you can get the instance using the "CreateInstance()" method. At the same time, we added Unity into our application and configured it using the standard configuration file.

The problem started when i was trying to map the interface IServiceLocator to get the instance of ServiceLocator and register it in the unity configuration file. As you probably guesses, ServiceLocator DOES NOT have a public constructor (i.e, singleton), hence, unity cannot create it when I do unity.resolve<IServiceLocator>()....

My question: Is there any way to tell Unity (through the configuration file) to use CreateInstance() instead of trying to execute the default constructor? If not, if you have any other idea what else can be done, I would appreciate to hear it.

Please don't suggest me to change the constructor to public, assume I can't do it for now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

无所谓啦 2024-08-21 11:46:35

您最好手动创建 UnityContainer 并将其注入到您的服务定位器中:

public class ServiceLocator 
{
    public static void SetServiceLocatorProvider(IServiceLocator serviceLocator)
    {
        Instance = serviceLocator;
    }

    public static void SetServiceLocatorProvider(Func<IServiceLocator> serviceLocator)
    {
        Instance = serviceLocator();
    }

    public static IServiceLocator Instance { get; private set; }
}


public class ServiceLocatorContainer : IServiceLocator
{
    private readonly IUnityContainer _unityContainer;

    public ServiceLocatorContainer(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }
//skipped for simplicity sake
 }


    public abstract class ApplicationControllerBase  
    {


        /// <summary>
        /// Создать экземпляр Unity контейнера
        /// </summary>        
        private IUnityContainer CreateContainer()
        {
            return new UnityContainer();
        }

        protected virtual void ConfigureContainer()
        {

            RegisterTypeIfMissing(typeof(IServiceLocator), typeof(ServiceLocatorContainer), true);
            RegisterTypeIfMissing(typeof(ISharedAssemblyInitializer), typeof(SharedAssemblyInitializer), true);

            ServiceLocator.SetServiceLocatorProvider(() => this.Container.Resolve<IServiceLocator>());

        }


    protected void RegisterTypeIfMissing(Type fromType, Type toType, bool registerAsSingleton)
    {

        if (Container.IsTypeRegistered(fromType))
        {

        }
        else
        {
            if (registerAsSingleton)
            {
                Container.RegisterType(fromType, toType, new ContainerControlledLifetimeManager());
            }
            else
            {
                Container.RegisterType(fromType, toType);
            }
        }
    }


        public virtual void Run()
        {
            this.Container = CreateContainer();
            this.ConfigureContainer();
        }

        public IUnityContainer Container { get; private set; }
}

这是 prism 扩展到 unity 的简化版本。请参阅 prism 中的 modulemanager 类的更详细来源。
应用程序以 Run 方法启动。您创建容器并在其中注册您的服务定位器。在注册时,UnityContainer 创建它的实例并将其自身传递给 ctor:

public ServiceLocatorContainer(IUnityContainer unityContainer)
{
    _unityContainer = unityContainer;
}

然后,使用 SetServiceLocatorProvider 方法将其分配给 servicelocator 类的 Instance 属性实例,该实例引用了内部的 Unity 容器。这种解决方案还给出了具体 DI 容器的抽象。您可以从代码中的任何位置引用您的服务定位器。
1)注入构造函数

public class RLoginABS
{

    IServiceLocator serviceLocator;

    public RLoginABS(IServiceLocator serviceLocator)
    {
        this.serviceLocator = serviceLocator;
    }

    public void Login(string user, string password)
    {            
        REnvironmentRWS environment = REnvironmentRWS.Current;            
        serviceLocator.RegisterInstance<IEnvironmentRWS>(environment as IEnvironmentRWS);
    }

}

或使用静态类:

shellViewModel = ServiceLocator.Instance.Resolve<IShellViewModel>();

ps:IServiceLocator接口,它是DI容器具体实现的抽象:

public interface IServiceLocator
{
    void Register<TInterface, TImplementor>() where TImplementor : TInterface;
    void Register(Type TInterface, Type TImplementor);
    void RegisterAsSingleton<TInterface, TImplementor>() where TImplementor : TInterface;
    T Resolve<T>();
}

它的方法包装了具体容器的方法,例如:

public void Register(Type TInterface, Type TImplementor)
{
    _unityContainer.RegisterType(TInterface, TImplementor);
}

希望 - 它有帮助!

You'd better create manually UnityContainer and inject it into your service locator:

public class ServiceLocator 
{
    public static void SetServiceLocatorProvider(IServiceLocator serviceLocator)
    {
        Instance = serviceLocator;
    }

    public static void SetServiceLocatorProvider(Func<IServiceLocator> serviceLocator)
    {
        Instance = serviceLocator();
    }

    public static IServiceLocator Instance { get; private set; }
}


public class ServiceLocatorContainer : IServiceLocator
{
    private readonly IUnityContainer _unityContainer;

    public ServiceLocatorContainer(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }
//skipped for simplicity sake
 }


    public abstract class ApplicationControllerBase  
    {


        /// <summary>
        /// Создать экземпляр Unity контейнера
        /// </summary>        
        private IUnityContainer CreateContainer()
        {
            return new UnityContainer();
        }

        protected virtual void ConfigureContainer()
        {

            RegisterTypeIfMissing(typeof(IServiceLocator), typeof(ServiceLocatorContainer), true);
            RegisterTypeIfMissing(typeof(ISharedAssemblyInitializer), typeof(SharedAssemblyInitializer), true);

            ServiceLocator.SetServiceLocatorProvider(() => this.Container.Resolve<IServiceLocator>());

        }


    protected void RegisterTypeIfMissing(Type fromType, Type toType, bool registerAsSingleton)
    {

        if (Container.IsTypeRegistered(fromType))
        {

        }
        else
        {
            if (registerAsSingleton)
            {
                Container.RegisterType(fromType, toType, new ContainerControlledLifetimeManager());
            }
            else
            {
                Container.RegisterType(fromType, toType);
            }
        }
    }


        public virtual void Run()
        {
            this.Container = CreateContainer();
            this.ConfigureContainer();
        }

        public IUnityContainer Container { get; private set; }
}

this is a simplified version of prism extension to unity. see more detailed sources of modulesmanager class in prism.
app starts with Run method. You create container and register your servicelocator in it. Wile registering, UnityContainer creates instance of it and pass itself into ctor:

public ServiceLocatorContainer(IUnityContainer unityContainer)
{
    _unityContainer = unityContainer;
}

then, using SetServiceLocatorProvider method you assign to Instance property instance of servicelocator class, that has reference to unity container within. Such solution also gives abstraction of concrete DI container. And you can reference to your service locator from anywhere in your code.
1) Injectiong into constructor

public class RLoginABS
{

    IServiceLocator serviceLocator;

    public RLoginABS(IServiceLocator serviceLocator)
    {
        this.serviceLocator = serviceLocator;
    }

    public void Login(string user, string password)
    {            
        REnvironmentRWS environment = REnvironmentRWS.Current;            
        serviceLocator.RegisterInstance<IEnvironmentRWS>(environment as IEnvironmentRWS);
    }

}

or using static class:

shellViewModel = ServiceLocator.Instance.Resolve<IShellViewModel>();

ps: IServiceLocator interface, which is an abstraction of concrete implementation of DI container:

public interface IServiceLocator
{
    void Register<TInterface, TImplementor>() where TImplementor : TInterface;
    void Register(Type TInterface, Type TImplementor);
    void RegisterAsSingleton<TInterface, TImplementor>() where TImplementor : TInterface;
    T Resolve<T>();
}

its methods wraps concrete container's methods, for example:

public void Register(Type TInterface, Type TImplementor)
{
    _unityContainer.RegisterType(TInterface, TImplementor);
}

Hope - it helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文