在这里,您将学习如何创建一个新的 StyletIoC 容器,并在其上注册您的服务。
要创建容器,您必须创建一个新的StyletIoCBuilder
,并在其上注册您的所有服务。StyletIoCBuilder.BuildContainer()
将已经被调用,所以你不需要调用它来构建你的容器。
例如:
// 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>();
如前所述,StyletIoC 的目的是接受对服务类型的请求,并使用您使用StyletIoCBuilder
. 不过,它可以使用几种不同的技术来创建该实例。
最简单的称为“类型绑定”。你告诉它服务类型,以及实现该服务的类型,它就会自己弄清楚如何构造该类型。例如:
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());
您可以自己构造一个类型的实例并将其交给 IoC 容器。这对于配置对象之类的东西很有用。例如:
builder.Bind<IVehicle>().ToInstance(new HotHatchback());
实例绑定是自动单例的——容器不知道如何构造该类型的新实例,因此必须始终返回相同的实例。
默认情况下,IoC 容器将IDisposable
在处理时处理实例类型,但您可以使用.ToInstance(foo).DisposeWithContainer(false);
.
默认情况下,StyletIoC 会在您每次询问时创建给定类型的新实例——这称为“瞬态作用域”。看:
var car1 = ioc.Get<IVehicle>();
var car2 = ioc.Get<IVehicle>();
// The following statement will succeed.
Assert.AreNotEqual(car1, car2);
IoC 容器不会处理IDisposable
瞬态类型——它不会声明对它们的所有权,也不知道何时应该处理它们。
但是,您也可以告诉它永远只创建一个服务实例,并在您每次询问时返回该实例。这称为“单例作用域”,如果您的应用程序确实有单例(大多数都有),这将非常有用,因为它使您免于拥有传统的单例对象,众所周知,传统的单例对象很难模拟单元测试。
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();
IoC 容器IDisposable
在处理时会处理单例。
到目前为止,我们已经尝试将单一类型绑定到单一服务。但是,事情并非必须如此。您_可以_将多种类型绑定到单个服务,例如:
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
- 如果您尝试获取单个IVehicle
with IContainer.Get
,StyletIoC 不知道要给您哪个,因此它会抛出异常。
这也适用于构造函数和参数注入,请参阅:
class Garage
{
public Garage(IEnumerable<IVehicle> vehicles) { ... }
}
// And
class Garage
{
[Inject]
public IEnumerable<IVehicle> Vehicles { get; set; }
}
StyletIoC 处理绑定泛型类型(其中类型参数的确切类型是已知的)与普通类型相同,例如:
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>>(); // 返回一个 Validator
服务及其实现都可以有任意多的类型参数,但它们必须有相同_数量_的类型参数(如果你想通了,这是有道理的)。但是,类型参数可以以任何顺序出现:
interface ISomeInterface<T, U> { ... }
class SomeClass<U, T> : ISomeInterface<T, U> { ... }
builder.Bind(typeof(ISomeInterface<,>)).To(typeof(SomeClass<,>));
StyletIoC 不考虑类型约束 - 如果您有一个interface IMyInterface
并请求一个IMyInterface
,您将得到一个异常。
StyletIoC 能够自动为您创建绑定。
自动绑定意味着如果您请求一个尚未在 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 上定义了几个扩展方法,这可能会让您的生活更轻松:
// 返回所有基础类型
someType.GetBaseTypes();
// 返回所有基础类型和接口
someType.GetBaseTypesAndInterfaces();
// 如果 someType 实现了 someServiceType,则返回 true
someType.Implements(someServiceType)
// 还考虑了泛型——所以这是真的:
typeof(Validator<int>>.Implements(typeof(IValidator<>));
项目原地址:https://github.com/canton7/Stylet
当前文档原地址:https://github.com/canton7/Stylet/wiki/StyletIoC-Configuration
上一篇:WPF的MVVM框架Stylet开发文档 4.1 StyletIoC 简介
下一篇:WPF的MVVM框架Stylet开发文档 14.3 StyletIoC 注入