WPF的MVVM框架Stylet开发文档 14.7-14.9 杂项、性能、技术

14.7 StyletIoC 杂项

文档地址

此页面包含其他各种值得一提的点点滴滴,但还不够大,不值得单独放置一个页面。

循环依赖

循环依赖项(下面记录的类型除外)会导致 StackOverflow 异常。提前发现这些问题并非易事,虽然 StackOverflow 异常并不理想,但不值得避免它的复杂性。

父/子循环依赖

假设你有这样的事情:

class Parent
{
    
    
   public Parent(Child child) {
    
     ... }
}

class Child
{
    
    
   public Parent Parent {
    
     get; set; }
}

您希望 StyletIoC 能够在其中创建 Parent 或 Child 的实例,并适当地创建另一个实例。

诀窍是使用工厂来创建两者,而不是使用容器来解析 Child 的实例并创建 Parent,反之亦然。这有点乱,但是无论如何循环依赖都是乱七八糟的。

Child 的 Parent 属性不能_有_属性[Inject],否则该BuildUp步骤将导致 StackOverflow。

builder.Bind<Parent>().ToFactory(container =>
{
    
    
   var child = new Child();
   container.BuildUp(child); // 如果child需要进行属性注入,则进行构建
   var parent = new Parent(child);
   child.Parent = parent;
   return parent; // parent将由 StyletIoC 自动建立
});
builder.Bind<Child>().ToFactory(container =>
{
    
    
   var child = new Child();
   var parent = new Parent(child);
   container.BuildUp(parent); // 如果parent需要进行属性注入,则进行构建
   child.Parent = parent;
   return child; // child将由 StyletIoC 自动建立
});

14.8 StyletIoC 性能

文档地址

很难比较不同 IoC 容器的性能。增加的复杂性通常会以性能为代价,因此功能更多的包含几乎总是会变慢。

然而,这些数字看起来非常有趣,所以这里是 Munq 的基准测试,修改后添加了 StyletIoC。

Running 500000 iterations for each use case.
                          Test:        Ticks -         mSec -   Normalized
              No IOC Container:      153,169 -        92.47 -         1.00
                     StyletIoC:      418,840 -       252.86 -         2.73
                          Munq:    3,009,272 -     1,816.74 -        19.65
                         Unity:   48,533,016 -    29,300.02 -       316.86
                       Autofac:   69,065,954 -    41,696.02 -       450.91
                  StructureMap:   15,356,998 -     9,271.22 -       100.26
                      Ninject2:  269,115,738 -   162,468.69 -     1,756.99
                       Windsor:  191,559,858 -   115,647.19 -     1,250.64
              StyletIoCFactory:    3,082,670 -     1,861.05 -        20.13
                   MunqFactory:    2,777,705 -     1,676.94 -        18.13
                AutofacFactory:   18,526,411 -    11,184.64 -       120.95
           StructureMapFactory:   15,708,059 -     9,483.16 -       102.55
               Ninject2Factory:  197,354,786 -   119,145.67 -     1,288.48
    No IOC Container Singleton:       27,382 -        16.53 -         0.18
            StyletIoCSingleton:      183,638 -       110.86 -         1.20
                 MunqSingleton:      411,133 -       248.21 -         2.68
                UnitySingleton:    8,048,317 -     4,858.87 -        52.55
              AutofacSingleton:    3,205,066 -     1,934.94 -        20.93
         StructureMapSingleton:    5,007,675 -     3,023.20 -        32.69
             Ninject2Singleton:   30,795,175 -    18,591.45 -       201.05
              WindsorSingleton:    2,379,411 -     1,436.48 -        15.53
                          Hiro:      252,305 -       152.32 -         1.65

在顶部没有后缀的条目中,容器负责确定如何实例化该类型,例如 builder.Bind<ISomeType>().To<SomeType>()。以 ‘Factory’ 结尾的条目是通过使用 builder.Bind<ISomeType>().To(container => new SomeType(container.Get<ISomeDependency>())) 进行绑定创建的,而以 ‘Singleton’ 结尾的条目是容器配置为始终为每个类型返回相同的实例。

扫描二维码关注公众号,回复: 15188883 查看本文章

一个有趣的观察是,StyletIoC 并不比简单地实例化类型慢多少——事实上,StyletIoC 实际上实例化类型的速度与本机代码一样快,它正在确定要实例化的类型,这会增加额外的。

另一个是,在 Factory 和 Singleton 情况下,StyletIoC 的速度与 Munq 几乎相同。然而,当容器负责确定如何实例化类型本身的实例时,StyletIoC 的速度要快一个数量级以上。这要感谢对 C# 表达式的一些巧妙使用,这在StyletIoC Technical中有所介绍。

14.9 StyletIoC 技术

文档地址

此页面是为想要深入研究 StyletIoC 源代码以验证它或提交拉取请求的人准备的背景阅读材料。

表达式:如何快速实例化一个类型

在运行时创建类型实例的传统方法是使用 Activator.CreateInstance,例如 Activator.CreateInstance(instanceType, new object[] { container.Get(param1Type), container.Get(param2Type) })。然而,这样做速度非常慢,大多数 IoC 容器不再使用它(如果它们曾经使用过)。

C# 3 引入了表达式树,C# 4 对其进行了扩展。表达式树可以用于生成指定某些操作(例如 a + b)的表达式,并在运行时将其编译为 IL 作为委托。这允许您使用例如 Expression.New(intanceType) 编写表达式,并将其编译为与手动编写 new Instance() 一样快的委托。

许多 IoC 容器采用了这种方法,并使用它来编写表达式,描述代码中的 Instance(container.Get(param1Type), container.Get(param2Type))。这比 Activator.CreateInstance 快得多,但仍需要为每个要解析的参数访问 IoC 容器,从而产生额外的开销。

StyletIoC 更进一步,生成描述 new Instance(new Param1Instance(), new Param2Instance()) 的代码表达式,这样做速度更快。

当其中一个参数需要属性注入时,也会使用此技巧,创建一个等效于以下内容的表达式:

var param1 = new Param1Instance();
param1.SomeProperty = new SomePropertyInstance();
new Instance(param1, new Param2Instance());

创作者和注册

StyletIoC 主要围绕着两个重要接口展开:ICreatorIRegistration

ICreator 知道如何提供一个类型的实例 - TypeCreator 知道如何创建一个类型的实例(如果你使用 Bind<..>().To<...>() 注册一个类型,就会使用它),而 FactoryCreator 则知道如何使用你指定的工厂创建一个实例(使用 Bind<..>().ToFactory(...))。

IRegistration 负责实例的生命周期,会在需要时使用它拥有的 ICreator 创建类型的新实例。TransientRegistration 每次都会创建一个新实例,而 SingletonRegistration 只会调用它的 ICreator 一次,并缓存结果实例。大多数情况下都使用 TransientRegistration,但如果你使用 .InSingletonScope() 指定一个单例,则会使用 SingletonRegistration

还有一个更复杂的部分,就是 IRegistrationCollection,它由 SingleRegistration(拥有单个 IRegistration)和 RegistrationCollection(拥有一组 IRegistration)实现。这主要是为了优化 - IRegistrationCollection 可以被要求提供一个单独的 IRegistration,也可以提供多个,而 RegistrationCollection 会在前者的情况下引发异常。

在 StyletIoC 的核心是一个字典,它的键是 [serviceType,key],值是 IRegistrationCollection。当你调用 IContainer.Get 时,StyletIoC 会找到正确的 IRegistrationCollection,并向它请求单个 IRegistration。然后,它将要求该 IRegistration 提供其类型的实例。

GetAll 注册

当请求注册项的集合时,情况会稍微复杂一些。StyletIoC还有一个字典,其键为 [elementType,key],值为 IRegistration,其中该 IRegistrationGetAllRegistration。给定一个 IEnumerable<T>,您可以提取 T,然后使用它从此字典中获取一个 IRegistration。该 IRegistration 可以创建一个包含所有正确元素的 List<T>

该字典由 IContainer.GetAll 和负责构造函数和属性注入的代码的部分使用,当它们遇到 IEnumerable<T> 时。

当需要时,此字典将即时填充。

未绑定的泛型

当您注册一个未绑定泛型类型时(例如 builder.Bind(typeof(IValidator<>)).To(typeof(Validator<>))),StyletIoC会将一个条目添加到 [未绑定泛型类型, key] => List<UnboundGeneric> 字典中。如果您请求的泛型类型不在注册字典中,StyletIoC会查看是否可以使用此字典中的任何条目构造该类型。如果可以,它将创建一个新的 IRegistration,并将其添加到注册字典中。

BuilderUppers

另外有一个字典也是解决方案的一部分,它是type => BuilderUpper。每个BuilderUpper都知道如何在该类型的实例上执行属性注入。当您调用IContainer.BuildUp时,会查询此字典,检索相关的BuilderUpper(如果它不存在则创建),并用于构建您的类型。它也被ICreator用于执行属性注入。

项目原地址:https://github.com/canton7/Stylet

上一节:WPF的MVVM框架Stylet开发文档 14.6 StyletIoC 模块

上一篇:WPF的MVVM框架Stylet开发文档 13.验证模型基类 ValidatingModelBase
下一篇:WPF的MVVM框架Stylet开发文档 15. 视图管理器 The ViewManager

猜你喜欢

转载自blog.csdn.net/qq_39427511/article/details/130410401