【问题标题】:ReactiveUI, View/ViewModel injection and DI in generalReactiveUI、View/ViewModel 注入和一般的 DI
【发布时间】:2015-01-09 23:29:11
【问题描述】:

最近我试图让自己进入 UI 开发的新时代并发现了 ReactiveUI。我喜欢它的声明性。

我想做一个完整的切换,所以我试图了解在这个 ReactiveUI 的新世界中是如何制作的。我选择 ReactiveUI 是因为我看到它是由一个非常聪明的人(Paul C. Betts)维护的。

我对它很陌生,我很可能会向 StackOverflow 提出关于它的问题,因为我拥有巨大的力量,我认为它值得学习和掌握

让我们进入细节:

我一直使用视图优先。我是 Cinch 框架的资深用户 (http://cinch.codeplex.com/)

它使用 MEF 将 ViewModel 注入每个 View。您只需用 [ViewModel("SampleView")] 装饰您的 ViewModel 并向您的视图添加一个附加属性 (ViewModelLocator.ViewModel="SampleView"),并且每当加载视图时,相应的 ViewModel 就会被实例化并作为其注入DataContext 与您选择的生命周期。

这种机制虽然有效,但也有一些不便之处。其中最糟糕的是:它使用定位器。

正如 Mark Seemann 在他的书中所说,ServiceLocator 是一种应该避免的反模式。

  1. 所以我的第一个问题是:ReactiveUI 是建立在 基于定位器的基础架构?
  2. 视图优先还是视图模型优先?对于像我这样的疯狂的、支持微软的清洁代码爱好者来说,在良好实践、解耦、SOLID 和类似的东西方面有什么更好的呢?哪个能让我睡得更好,并为我的应用程序提供所有这些*能力优点?

【问题讨论】:

    标签: c# mvvm reactiveui


    【解决方案1】:

    Paul 可能会附和官方的回答,但作为一个在几个项目中使用过该框架但绝不是专家的人,我会投入 0.02 美元。

    1) 我是 Mark Seemann 的忠实粉丝,我同意他关于 ServiceLocator 反模式的结论。虽然 ReactiveUI 确实使用了定位器“Splat”,但我不会认为它是建立在基于定位器的基础设施之上的。有一些全局项目像线程调度程序和一些主要设置一样使用,但这些主要是在应用程序启动时设置的(就像任何 DI 容器一样),而且大部分情况下您不会直接在类中处理它们。唯一真正的位置是 ViewModelHost 控件,它使用视图上的特定接口 (IViewFor) 来注册 ViewModel。这比属性方法要好,因为它让 ViewModel 幸福地不知道 View。但这发生在控件本身并且是框架的一部分,所以我不认为这是对 ServiceLocator 反模式的滥用。我觉得这与在设置 DI 容器时注册任何其他内容没有什么不同。

    2) 根据我使用 ReactiveUI 以来的经验,我的视图变得非常简单。基本上使用一些基本的 XAML 来获得正确的外观和布局,在后面的代码中实现 IViewFor,并在构造函数中完成我的所有绑定,我发现现在使用 ReactiveUI 比在 XAML 中更容易(尽管如果你仍然可以你想要)。然后所有的逻辑都在 ViewModel 中完成。我认为我通常只使用 ViewModel First 方法,因为我需要定义它(或至少它的接口)以在 View 上为它实现IViewFor<>。我喜欢类型检查和其他东西(我喜欢在构造函数中而不是在 XAML 中绑定的另一个原因)。但根据我的经验,我不认为有充分的理由这样做。

    【讨论】:

      【解决方案2】:

      ServiceLocator 是一种应该避免的反模式。

      我通常认为很多关于 IoC/DI 的建议在“跨平台移动应用程序”领域都非常糟糕,因为你必须记住,他们的很多想法都是为网络应用程序编写的,而不是为移动应用程序或移动应用程序编写的。桌面应用程序。

      例如,绝大多数流行的 IoC 容器只关心温缓存上的解析速度,而基本上完全不考虑内存使用或启动时间 - 这对于服务器应用程序来说是 100% 没问题的,因为这些都不重要;但对于移动应用程序?启动时间巨大

      Splat 的 Service Location 解决了 RxUI 的许多问题:

      1. 服务位置快速,几乎没有设置开销。
      2. 它封装了几种不同的常见对象生命周期模型(即'create new every time'、'singleton'、'lazy'),只是通过不同的 Func 编写方式
      3. 它对 Mono 链接器友好(通常)
      4. 服务位置允许我们在特定于平台的代码中注册类型,但在 PCL 代码中使用它们。

      服务定位器的最佳使用方式

      事实上,我大体上同意 Mark Seemann 的观点,因为构造函数注入是首选的方式——这是我真正喜欢的模式:

          public SuspensionHost(ISuspensionDriver driver = null)
          {
              driver = driver ?? Locator.Current.GetService<ISuspensionDriver>();
          }
      

      这使用服务定位接口作为默认接口,但前提是调用者没有在构造函数中给出明确的接口。在单元测试运行程序中进行测试比尝试构建假 IoC 容器要简单得多,但仍会在运行时回退到默认实现。

      视图优先还是视图模型优先?

      是否可以在 ReactiveUI 中使用基于 VM 的路由(即 RoutedViewHost、IScreen、RoutingState 和朋友)取决于您所在的平台:

      • WPF、Xamarin 形式:绝对可以
      • WP8,WinRT:你可以让它工作,你失去了一些过渡和细节
      • Android、iOS 原生:很难工作

      【讨论】:

      • 看看 DryIoc.Zero,它解决了注册慢的问题,但提供了惊人的功能。
      • 仍然不喜欢我必须依赖静态定位器而不是可以在外部项目中轻松模拟的注入接口类型这一事实。至少应该有一个选项来避免以当前形式使用Locator
      • 关于路由,是否有用于引导和路由的平台无关技术?我正在开始一个新的客户端项目,该项目将使用Uno Platform 编写,之所以选择该项目是因为我可以编写一个简单的 UWP 应用程序,该应用程序可以在桌面、移动设备和 Web 上编译和呈现。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 2018-03-16
      相关资源
      最近更新 更多