【问题标题】:Make sure that one static class is created before the other确保一个静态类在另一个之前创建
【发布时间】:2016-09-08 14:33:24
【问题描述】:

我正在开发一个 C#/WPF/MVVM/UWP 应用程序,它使用如下所示的 ViewModelLocator:

    public class ViewModelLocator
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
        "CA1822:MarkMembersAsStatic",
        Justification = "This non-static member is needed for data binding purposes.")]
    public MainPageViewModel MainPage
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainPageViewModel>();
        }
    }


    static ViewModelLocator()
    {
        // DEBUG LINE: var test = Views.ViewLocator.MainPageKey;
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
        }
        else
        {
            SimpleIoc.Default.Register<IDataService, DataService>();
        }

        SimpleIoc.Default.Register<MainPageViewModel>();
    }
}

我有另一个类,一个 ViewLocator,用于导航目的,如下所示:

    public class ViewLocator
{
    public static readonly string MainPageKey = typeof(MainPage).Name;
    public static readonly string WorkPageKey = typeof(WorkPage).Name;

    static ViewLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        var navigationService = new NavigationService();

        navigationService.Configure(MainPageKey, typeof(MainPage));
        navigationService.Configure(WorkPageKey, typeof(WorkPage));

        SimpleIoc.Default.Register<INavigationService>(() => navigationService);

        SimpleIoc.Default.Register<IDialogService, DialogService>();
    }
}

之前,这两个类都合并在 ViewModelLocator 中,但是我认为 ViewModelLocator 作为“ViewModels-Side-of-things”的一部分应该不知道视图及其类型,这就是我将该代码重构为两个的原因类。

然后我的 MainPageView 有一个按钮,它触发 MainPageView.cs 中的导航命令

    public class MainPageViewModel : ViewModelBase
{
    private INavigationService _navigationService;

    public RelayCommand CreateNewImageCommand { get; private set; }

    public MainPageViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;

        CreateNewImageCommand = new RelayCommand(CreateNewImage, () => true);
    }

    public void CreateNewImage()
    {
        _navigationService.NavigateTo(Views.ViewLocator.WorkPageKey);
    }
}

为了完整起见,这是我的 App.xaml

<Application
...>

<Application.Resources>
    <v:ViewLocator x:Key="ViewLocator" />
    <vm:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

现在发生的情况是:如果我在 ViewModelLocator 中没有 DEBUG LINE,则在 MainPage 从 ViewModelLocator 请求其 ViewModel 时,尚未调用 ViewLocator 的构造函数,return ServiceLocator.Current.GetInstance&lt;MainPageViewModel&gt;(); 抛出异常.如果我包含 DEBUG LINE,这将强制 ViewLocator 构造函数首先运行,并且一切正常。

如果没有奇怪的调试行,我怎样才能实现这种行为?

【问题讨论】:

  • 我将把它留在这里Is ServiceLocator anti-pattern
  • TL;DR 你真的应该使用依赖注入而不是服务定位器模式。通常,如果从头开始,这是一种更好、更容易理解的模式。
  • @Liam 我不是 IoC Containers 或 ServiceLocator 或任何你想称呼它的粉丝。只是我一直在研究如何正确分离VM和V,这是迄今为止唯一让我满意的工作方法。然而,我对使用 DI 持开放态度——如果你能告诉我一些正确使用它的参考代码。
  • 大多数人使用IoC framework these days。例如Ninject
  • 看看 Caliburn Micro;它将为您完成繁重的工作,您将获得 IoC ......是的,IoC 是要走的路。

标签: c# wpf mvvm static-classes


【解决方案1】:

您遇到了大多数开发人员不使用静态类和服务定位器的原因。

按照您的 cmets 中的建议,尝试使用依赖注入。这允许对管理此布线的组件进行控制反转。

将 MEF 或 Unity 作为一个框架来使用,而不是滚动您自己的 IoC。两者都有优点和缺点,但任何一个都可以。它们还允许更轻松、更清洁的测试。

MEF

Unity

【讨论】:

    【解决方案2】:

    尽管有所有 cmets 和其他答案,但我认为我毕竟在赛道上。为了解决或绕过这个问题,我在应用程序的启动中创建了 SimpleIoC 容器的添加引导,并将代码从 ViewLocator 的构造函数移到那里。

    我还删除了 ServiceLocator 调用,这有点多余,现在直接依赖 SimpleIoC.Default

    导航器仍然由SimpleIoC 容器注入到 ViewModels 中。然而,ViewModelLocator 是与 XAML 代码结合使用的必要工作。

    我建议将此答案作为其他同样在此问题上苦苦挣扎的人的起点。

    https://stackoverflow.com/a/25524753/2175012

    毕竟,我认为 ServiceLocators 不是反模式,但必须小心使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-24
      • 2016-09-10
      • 2022-01-04
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多