zoukankan      html  css  js  c++  java
  • 轻量级MVVM框架Stylet介绍:(14) StyletIoC

    简介

    StyletIoC轻量级的极快速的IoC容器。

    服务和构建

    StyletIoC是围绕服务的概念构建的。服务是具体类型、抽象类型或接口,由具体类型实现,例如:

    interface IVehicle { ... }
    class HotHatchback : IVehicle { ... }
    

    这里IVehicle是服务,HotHatchback是实现它的具体类型。请注意,HotHatchback也是一个服务 - 由类本身实现的服务。

    配置 StyletIoC 时,需要定义一组关系。每个关系都介于服务与实现它的类型(或多个类型)之间。所以在这里,我们可以告诉StyletIoC"在服务IVehicle和类型HotHatchback之间建立一种关系"。

    稍后,当你想要实现IVehicle时,你可以要求StyletIoC"给我一个实现IVehicle服务的实例,StyletIoC将构造一个HotHatchback并将其传回给你。

    解析类型 - 服务定位器和注入

    有3种方法可以让StyletIoC为我们构建一个类型:

    • 通过直接调用IContainer.Get
    • 构造函数注入
    • 属性注入

    直接调用IContainer.Get,如下例:

    var ioc = ... // Covered in lots of detail elsewhere
    var vehicle = ioc.Get<IVehicle>();
    

    看起来很简单,但是缺点是只能在应用程序的根目录才能这样做,在其他地方还是需要使用构造函数和参数注入。

    构造函数注入的例子

    class Engine { ... }
    class Car
    {
       public Car(Engine engine)
       {
          // 'engine' contains a new instance of Engine
       }
    }
    

    属性注入的例子:

    class Engine { ... }
    class Car
    {
       [Inject]
       public Engine Engine { get; set; }
    }
    

    StyletIoC Configuration

    入门 - 构建器

    使用StyletIoC容器的方法是首先调用StyletIoCBuilder构建容器,然后在其上注册服务。例如:

    // First, create the builder
    var builder = new StyletIoCBuilder();
    
    // Configure the builder
    builder.Bind<IVehicle>().To<HotHatchback>();
    
    // The container is then built for you
    
    // Now you can use this to resolve instances of services
    var vehicle = ioc.Get<IVehicle>();
    

    创建类型的不同方式

    类型绑定

    代码如下:
    builder.Bind<IVehicle>().To<HotHatchback>();
    这表示告知StyletIoC:每当要求提供一个IVehicle的实现,就使用适当的构造函数创建一个HotHatchback的新实例,并将所必要的依赖传入。

    也可以将服务绑定到自身,这是一种类型约束,称之为“自绑定”,例如:

    builder.Bind<HotHatchback>().To<HotHatchback>();
    // Or, more clearly:
    builder.Bind<HotHatchback>().ToSelf();
    

    这表示告知StyletIoC:每当要求提供一个HotHatchback的实现,就给出一个早已包含所有依赖的HotHatchback。

    也可以使用非范型版本:
    builder.Bind(typeof(IVehicle)).To(typeof(HotHatchback));

    工厂绑定

    可以告知StyletIoC如何构建类型,传入一个委托,称之为“工厂缄定”,例如:

    builder.Bind<IVehicle>().ToFactory(container => new HotHatchback());

    这里的container参数是IContainer类型,可以用来注入构造函数中必要的依赖,例如:

    builder.Bind<IVehicle>().ToFactory(container => new HotHatchback(container.Get<Engine>()));

    当然,这里也支持自绑定:

    builder.Bind<HotHatchback>().ToFactory(container => new HotHatchback());

    实例绑定

    也可以将一个自己创建的实例注入容器,例如:
    builder.Bind<IVehicle>().ToInstance(new HotHatchback());
    实例绑定原生是单例的,因为容器不知道如何构建该类型的新实例,因此始终返回相同的实例。

    作用范围

    Transient

    默认情况下,StyletIoC每次都会创建一个新的实例,称之Transient:

    var car1 = ioc.Get<IVehicle>();
    var car2 = ioc.Get<IVehicle>();
    
    // The following statement will succeed.
    Assert.AreNotEqual(car1, car2);
    

    IoC容器不会主动释放Transient实例,如果需要,请手动处理。

    单例

    你可以告知IoC仅创建唯一一个服务的实例,这有利于单元测试:

    builder.Bind<IConfigurationManager>().To<ConfigurationManager>().InSingletonScope();
    var ioc = builder.BuildContainer();
    
    var configManager1 = ioc.Get<IConfigurationManager>();
    var configManager2 = ioc.Get<IConfigurationManager();
    
    // The following statement will succeed.
    Assert.AreEqual(configManager1, configManager2);
    

    当然也可以使用工厂绑定方式构建单例:
    builder.Bind<IConfigurationManager>().ToFactory(container => new ConfigurationManager()).InSingletonScope();

    采用不同方式构建的单例并不是同一对象:

    builder.Bind<IConfigurationManager>().To<ConfigurationManager>().InSingletonScope();
    builder.Bind<ConfigurationManager>().ToSelf();
    
    var ioc = builder.BuildContainer();
    
    var configManager1 = ioc.Get<IConfigurationManager>();
    var configManager2 = ioc.Get<ConfigurationManager>();
    
    // The following statement will succeed.
    Assert.AreNotEqual(configManager1, configManager2);
    

    如果你想要让其返回同一实例,可以这样做:

    builder.Bind<ConfigurationManager>().And<IConfigurationManager>().To<ConfigurationManager>().InSingletonScope();

    将多个类型绑定到单一服务

    例如:

    interface IVehicle { ... }
    class HotHatchback : IVehicle { ... }
    class OldBanger : IVehicle { ... }
    
    builder.Bind<IVehicle>().To<HotHatchback>();
    builder.Bind<IVehicle>().To<OldBanger>();
    
    var ioc = builder.BuildContainer();
    
    // This will throw an exception
    ioc.Get<IVehicle>();
    
    // This will return { new HotHatchback(), new OldBanger() }
    IEnumerable<IVehicle> vehicles = ioc.GetAll<IVehicle>();
    

    如果需要获取集合,应该使用IContainer.GetAll方法,使用IContainer.Get,因为无法判断是哪一个,会抛出异常。

    这个规则同样适用于构造函数及参数注入:
    class Garage
    {
    public Garage(IEnumerable vehicles) { ... }
    }

    // And

    class Garage
    {
    [Inject]
    public IEnumerable Vehicles { get; set; }
    }

    绑定范型

    范型绑定的方法与上面类似:

    interface IValidator<T> { ... }
    class IntValidator : IValidator<int> { ... }
    builder.Bind<IValidator<int>>().To<IntValidator>();
    
    interface IValidator<T> { ... }
    class Validator<T> : IValidator<T> { ... }
    builder.Bind<IValidator<int>>().To<Validator<int>>();
    

    有趣的是,可以为未知的泛型类型创建绑定:

    interface IValidator<T> { ... }
    class Validator<T> : IValidator<T> { ... }
    builder.Bind(typeof(IValidator<>)).To(typeof(Validator<>));
    
    var ioc = builder.BuildContainer();
    
    var intValidator = ioc.Get<IValidator<int>>(); // Returns a Validator<int>
    

    服务及其实现都可以有任意数量的类型参数,但它们必须有相同数量的类型参数(如果你仔细考虑的话,这是有道理的)。 但是,类型参数可以按任何顺序出现:

    interface ISomeInterface<T, U> { ... }
    class SomeClass<U, T> : ISomeInterface<T, U> { ... }
    builder.Bind(typeof(ISomeInterface<,>)).To(typeof(SomeClass<,>));
    

    StyletIoC 不考虑类型约束——如果你有一个接口 IMyInterface where T: class 并请求一个 IMyInterface,你会得到一个异常。

    自动绑定

    自动绑定所有实体类型

    自动绑定意味着如果您请求一个尚未向 Stylet 注册的具体类型,Stylet 将尝试为您构建它作为临时实例。 它仅适用于您指定的程序集中的类型:StyletIoCBuilder.Assemblies 中的类型,以及您传递给 Autobind 方法的任何程序集中的类型。

    请注意,显式绑定始终优先于自动绑定。

    将诸如 mscorlib 之类的程序集传递给 Autobind 是一个坏主意,否则 Stylet 将尝试实例化诸如 System.String 之类的类型。

    builder.Autobind();
    这在 MVVM 应用程序中很有用,因为它允许 StyletIoC 解析您的任何 ViewModel。 Stylet 引导程序调用 Autobind(),这意味着默认情况下启用自动绑定。

    绑定一个服务到所有实现

    interface IVehicle { ... }
    class HotHatchback : IVehicle { ... }
    class OldBanger : IVehicle { ... }
    
    builder.Bind<IVehicle>().ToAllImplementations();
    
    var ioc = builder.BuildContainer();
    
    IEnumerable<IVehicle> vehicles = ioc.GetAll<IVehicle>(); // Returns { new HotHatchback(), new OldBanger() }
    

    还有一些重载允许您指定要搜索的程序集。

    这本身就很有用(想想查找所有插件),但在与未绑定的泛型结合使用时特别有用。 例如:

    interface IValidator<T> { ... }
    class IntValidator : IValidator<int> { ... }
    class StringValidator : IValidator<string> { ... }
    
    builder.Bind(typeof(IValidator<>)).ToAllImplementations();
    
    var ioc = builder.BuildContainer();
    
    var intValidator = ioc.Get<IValidator<int>>(); // Returns an IntValidator
    var stringValidator = ioc.Get<IValidator<string>>(); // Returns a StringValidator
    

    如果你想要更复杂的绑定规则,StyletIoC 并没有为你提供 API——你自己做几乎不需要任何努力,而提供 API 只是增加了很多复杂性而收效甚微。

    但是,StyletIoC 确实在 Type 上定义了一些扩展方法,这可能会让您的生活更轻松:

    // Returns all base types
    someType.GetBaseTypes();
    
    // Returns all base types and interfaces
    someType.GetBaseTypesAndInterfaces();
    
    // Returns true if someType implements someServiceType
    someType.Implements(someServiceType)
    // Also takes into account generics - so this is true:
    typeof(Validator<int>>.Implements(typeof(IValidator<>));
    
  • 相关阅读:
    Dictionary用法详解
    List与IList的区别
    接口
    C# List<T>用法详解
    c#FileStream文件读写
    学习如何用VS2010创建ocx控件
    sql server零碎知识
    BinaryWriter和BinaryReader用法
    通讯录源程序分析
    美丽说
  • 原文地址:https://www.cnblogs.com/qouoww/p/15806073.html
Copyright © 2011-2022 走看看