轻量级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<>));
原文地址:https://www.cnblogs.com/qouoww/p/15806073.html