代码之家  ›  专栏  ›  技术社区  ›  devuxer

SimpleServiceLocator:为什么单例不支持自动构造函数注入?

  •  1
  • devuxer  · 技术社区  · 14 年前

    我一直在试验 SimpleServiceLocator 依赖项 . 您必须手动创建singleton对象、它的所有依赖项、它的所有依赖项等。

    为什么SimpleServiceLocator是这样设计的?

    难道单例不应该和普通实例一样,只是在第一次请求实例时,该实例被存储并重用,而不是每次都创建一个新实例吗?为什么SimpleServiceLocator要求在注册过程中提供实例,而不是只允许在第一次请求时创建和存储实例?

    RegisterSingle<T>() 而不是 Register<T>() . 有没有一个更复杂(似乎不太方便)的设计,我只是不明白的原因?

    同时,我是否可以使用另一个(最好是免费的)IOC容器,让我在代码中注册类似于SimpleServiceLocator的对象,但是允许单例的自动构造函数注入(或者至少允许单例的依赖项的自动构造函数注入)?

    2 回复  |  直到 13 年前
        1
  •  2
  •   Steven    14 年前

    这个 RegisterSingle<T> 也可以用 Register<T> 方法。 The web site gives examples of this 注册<T> 方法如下(它使用闭包):

    var weapon = new Katana();
    container.Register<IWeapon>(() => weapon);
    

    当你看着 lifestyle management examples 在网站上,您可以看到以下创建线程静态实例的示例:

    [ThreadStatic]
    private static IWeapon weapon;
    
    container.Register<IWeapon>(
        () => return weapon ?? (weapon = new Katana()));
    

    private static IWeapon weapon;
    
    container.Register<IWeapon>(
        () => weapon ?? (weapon = container.GetInstance<Katana>()));
    

    这里的诀窍是将实例存储在一个静态变量中(就像静态线程一样),但是现在您不应该自己创建实例 new 将其初始化,但将创建委托给简单服务定位器。这是可行的,因为正如您所知,当请求具体类型时,SimpleServiceLocator将执行自动构造函数注入。

    正在添加的重载允许我们执行以下操作:

    container.RegisterSingle<IWeapon>(
        () => container.GetInstance<Katana>());
    

    更新:

    从0.14版开始,我们可以执行以下操作:

    container.RegisterSingle<IWeapon, Katana>();
    

    再容易不过了。

        2
  •  1
  •   Jay    14 年前

    典型的单例实现具有 private 构造函数,因此容器无法“看到”它、调用它或检测依赖项。

    这不是辛格尔顿的意思。尽管容器返回相同的实例,但是没有什么可以阻止您在代码中使用 new

    public class MySingleton
    {
        // note: not a thread-safe implementation
        static MySingleton instance;
        static DependencyThing thing;
    
        private MySingleton(DependencyThing thing)
        {
            MySingleton.thing = thing;
        }
    
        public static MySingleton GetMySingleton(DependencyThing thing)
        {
            if(instance == null) instance = new MySingleton(thing);
            return instance;
        }
    }
    

    如你所见,你不能打电话 new MySingleton() 在课堂之外。要“实例化”MySingleton,必须调用 MySingleton.GetMySingleton(thing) . 此调用返回唯一的实例或创建然后返回它。

    SimpleServiceLocator

    如果API公开了类似

    public void Register<T>(Expression<Func<T>> staticFactoryMethod)…
    

    在这种情况下你可以打电话 Register(() => MySingleton.GetMySingleton()); ,但这只能在没有参数的情况下工作。必须有更多的过载:

    public void Register<T, TParam1>(Expression<Func<TParam1, T>> staticFactoryMethod)…
    public void Register<T, TParam1, TParam2>(Expression<Func<TParam1, TParam2, T>> staticFactoryMethod)…
    

    以便容器知道实例化哪些依赖项并传递给指定的工厂方法。

    GetMySingleton 将不得不忽略参数或改变单例的状态,这几乎肯定是一个非常糟糕的主意。