3

这对某些人来说可能很明显,但是......有没有办法用 LightInject 解决非注册类型?此外,在没有显式注入的情况下使用 DI 框架自动神奇地解析对象以提高可读性是一种好习惯吗?

在我的示例中,我将超级全功能框架(可能是最慢的)与最轻量(和最快)的框架之一进行比较。这不完全是一个错误:D

构造函数注入(无容器)

    private static void ComposeObjects()
    {
        var repository = new CSVRepository();
        var viewModel = new PeopleViewerViewModel(repository);
        Application.Current.MainWindow = new PeopleViewerWindow(viewModel);
    }

忍者

    private void ConfigureContainer()
    {
        Container = new StandardKernel();
        Container.Bind<IPersonRepository>().To<CSVRepository>()
            .InSingletonScope();
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.Get<PeopleViewerWindow>();
    }

统一

    private void ConfigureContainer()
    {
        Container = new UnityContainer();
        Container.RegisterType<IPersonRepository, CSVRepository>(
            new ContainerControlledLifetimeManager());
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.Resolve<PeopleViewerWindow>();
    }

光注入

    private void ConfigureContainer()
    {
        Container = new ServiceContainer();
        Container.Register<IPersonRepository, CSVRepository>(
            new PerContainerLifetime());

        // Do we need to explicitly register PeopleViewerWindow with LightInject?

        Container.Register<PeopleViewerWindow>(
          factory =>
            new PeopleViewerWindow(new PeopleViewerViewModel
              (Container.GetInstance<IPersonRepository>()))
          );
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.GetInstance<PeopleViewerWindow>();
    }
4

3 回答 3

2

LightInject 可以使用RegisterFallback方法解析未在容器中注册的服务。

var container = new ServiceContainer();
container.RegisterFallback((type, s) => true, request => new Foo());
var foo = container.GetInstance<IFoo>();

RegisterFallback方法的第一个参数可以决定服务是否可以“延迟解析”。第二个参数是一个ServiceRequest实例,它提供请求的服务类型和服务名称。

文档已使用此信息进行了更新。http://www.lightinject.net/

更新

根据您的示例代码,我怀疑您正在尝试克服 LightInject 不会自动解析未知具体类型的事实。

对于您当前的情况,我认为最好扫描程序集并搜索从某种类型继承的具体类型。例如,如果 viewmodel 基类继承自某种类型的类。

看看 LightInject.WebApi 中的这段代码,它使用类似的方法来注册控制器。

public static void RegisterApiControllers(this IServiceRegistry serviceRegistry, params Assembly[] assemblies)
{
    foreach (var assembly in assemblies)
    {
        var controllerTypes = assembly.GetTypes().Where(t => !t.IsAbstract && typeof(IHttpController).IsAssignableFrom(t));
        foreach (var controllerType in controllerTypes)
        {
            serviceRegistry.Register(controllerType, new PerRequestLifeTime());
        }
    }
}

此致

Bernhard Richter(LightInject 的作者)

于 2014-07-31T16:40:18.057 回答
1

我对 LightInject 不是很熟悉,所以我不知道是否可以解决未注册的类型,但我可以回答这个问题:

使用 DI 框架自动神奇地解析对象而不显式注入以提高可读性是一种好习惯吗?

我认为使用未注册的类型解析来解析未注册的类型是可以的。在某些情况下,不使用它甚至没有意义,例如在注册开放泛型类型时。如果没有这个,您将不得不显式注册每个 closes-generic 映射,这会导致您对组合根进行不断更改(或者您需要进行某种批量注册,在那里您可以搜索所有可用作类型参数的类型在您的泛型类型中并使用反射构建封闭的泛型版本并注册它们,呸)。

但是,您应该始终尝试实现的是具有可验证的 DI 配置。应该可以在应用程序启动期间或使用单元测试来验证容器的配置。IMO 对此进行测试至关重要,因为您需要通过引入依赖注入来补偿编译时支持的损失。您可以通过迭代容器的配置并请求容器解析每个注册来测试这一点(一些 DI 库包含帮助您解决此问题的功能),或者您要求容器显式解析所有根类型。

如果您选择迭代整个配置,这意味着至少需要在容器。否则,容器对该类型一无所知,因此不会对其进行测试,您最终会得到一个在运行时仍然可能失败的系统。

如果您选择迭代所有根类型,则无需显式注册它们,但您仍然需要一种通过反射找到所有根类型的方法。如果您不通过反射来完成,则意味着每次添加新的根类型时都必须更改单元测试。而且您有时会忘记更改测试,从而导致您的配置仅得到部分验证。这是要预防的。

所以我的偏好是显式注册根类型,这可能还有其他优点。一些 DI 库包含非常有用的诊断工具,可以告诉您有关对象图的各种有趣信息,并可以警告您常见的错误配置(例如Captive Dependencies)。这些工具显然只能在库知道的类型上完成它的工作。该库通常可以找到未显式注册的注册,只要它们是某些其他注册类型的依赖项,但这当然不适用于根类型。

于 2014-07-31T08:06:24.283 回答
0

正如您对 Unity 和 Ninject 所做的那样,我没有看到可以解决 LightInject 等相关依赖项的默认策略。我没有 LightInject 的经验,但至少他们的文档没有这样的示例。可能还有其他方法可以通过扫描程序集来实现这一点,但我会明确地注入它,如下所示。它将根据需要解析 PeopleViewerWindow 实例。

        var lightContainer = new ServiceContainer();
        lightContainer.Register<IPersonRepository, CSVRepository>
        (new PerContainerLifetime());
        lightContainer.Register<PeopleViewerWindow>(
            factory =>
                new PeopleViewerWindow(new PeopleViewerViewModel
                (lightContainer.GetInstance<IPersonRepository>())));

        var instance2 = lightContainer.GetInstance<PeopleViewerWindow>();
于 2014-07-31T02:38:47.380 回答