【问题标题】:How to create a class without constructor parameter which has dependency injection如何创建一个没有具有依赖注入的构造函数参数的类
【发布时间】:2019-03-01 17:31:11
【问题描述】:

我已将依赖注入添加到项目中。但是当我使用 new 关键字创建实例时,依赖注入不起作用。

public class MyClass
{
    ILoginTokenKeyApi _loginTokenKeyApi;

    public MyClass(ILoginTokenKeyApi loginTokenKeyApi)
    {
        _loginTokenKeyApi = loginTokenKeyApi;
    }

    ...
}

当我尝试创建 MyClass 的实例时,它希望自然地构造一个参数。

就像这样:

MyClass mc = new MyClass(); // ERROR, it wants a parameter (but it is what i want)

我必须这样做:

MyClass mc = new MyClass(new LoginTokenKeyClass()); // this is not a good code for me

我如何创建一个不带参数的 MyClass 实例,因为它注入了依赖项。

【问题讨论】:

  • 您是否尝试使用依赖注入注册 ILoginTokenKeyApi?它通常应该能够自动将参数插入到构造函数中。否则,如果您真的想创建一个没有 ILoginTokenKeyApi 对象的实例,请参阅关于属性注入的答案。如果您在单元测试的上下文中需要这个,您可能应该研究像 moq 这样的模拟框架。
  • @vasily.sib // 我已经对这篇文章进行了一些编辑,请再次检查。
  • 你使用的是什么 IoC 容器?
  • 好吧,当您使用依赖注入时,通常您不会自己创建实例。这是DI容器的责任。举个例子,你可以使用 Ninject 创建一个这样的实例:var instance = _kernel.Get<MyClass>();.
  • 请帮助我们为您提供帮助。您的问题非常不清楚,可能是因为您误解了依赖注入。为了帮助我们,请您阅读关于依赖注入的免费introductory chapterthis book。读完那章后,你能重新提出你的问题吗?

标签: c# asp.net asp.net-core dependency-injection parameter-passing


【解决方案1】:

但是当我使用new 关键字创建实例时,依赖注入不起作用。

这就是依赖注入的基本原理。

使用依赖注入,您根本不应该new 增加新对象。这就是dependency injectioninversion of control 的全部意义所在。您不是创建对象和管理这些对象的依赖项,而是依赖于框架您需要的依赖项,而无需您关心它们实际来自何处以及它们是如何正确构造的。因此,您将创建对象的责任转移到调用者身上。

如果您发现自己需要创建一个具有依赖关系的对象,那么这清楚地表明您做错了。一个常见的原因是您想要创建对象以管理其生命周期,或者因为它实际上是一个数据对象,恰好有一些需要其他依赖项才能工作的操作(例如,具有“保存“ 方法)。在第一种情况下,您根本不会那样做。您只需要依赖它并让框架管理生命周期;如果它的生命周期不正确,那么您应该使用 DI 容器重新配置它。

在后一种情况下,您有一个带有操作的数据对象,您应该将其拆分。您应该只拥有一个数据对象,没有任何逻辑,然后注入一些能够为您执行该数据对象操作的管理器服务。

例如,在 ASP.NET Core Identity 中,您拥有 User 对象,它只是一个没有任何逻辑的普通实体。为了例如添加用户角色或更改密码,您依赖于您可以注入的用户管理器。所以User 对象本身没有任何依赖关系。

我通常建议您阅读 ASP.NET Core 文档的dependency injection chapter,以了解依赖注入的工作原理以及它应该如何在框架中使用。

【讨论】:

  • “使用依赖注入,你根本不应该新建新对象。”。我明白你在这里想说什么,但这并不完全准确。 new 向上依赖完全很好,只要您在应用程序的启动路径中执行此操作,a.k.a. Composition Root。 DI 不需要使用 DI 容器,这种做法通常称为Pure DI。除此之外,我同意你的看法。
  • @Steven 当然,在这种情况下,那会很好。从问题的上下文来看,这是 ASP.NET Core,它确实有一个(强制性)DI 容器,因此 OP 正试图在依赖项中执行此操作(因为您根本无法访问这样的组合根) . - 但是,是的,你的评论是完全有效的,尽管考虑到 OP 的尝试,我确实认为它有点太深了 :)
  • 在 ASP.NET Core 中必须使用 DI 容器是一个常见的误解。事实并非如此。
  • @Steven 当整个框架使用依赖注入来组合其组件时,我很想看看如何在没有 DI 容器的情况下设置它。但老实说,我怀疑您是否能够在没有容器的情况下执行此操作,除非您正在谈论手动组合数百个(内部)依赖项。
  • my book的第7.3章实际上详细描述了如何在ASP.NET Core中应用Pure DI。您可以在this repository 中看到一个简短的演示。然而,何时选择 DI 容器而不是纯 DI 是一个更复杂的问题。这是第 12 章中讨论的内容。
【解决方案2】:

正如 cmets 中提到的,不清楚您要实现什么,但为了在 .Net Core 中进行 DI,您必须创建一个接口 IMyClass,然后让您的类实现该接口,

public interface IMyClass {
   void SampleMethod();
}

public class MyClass : IMyClass
{
    ILoginTokenKeyApi _loginTokenKeyApi;

    public MyClass(ILoginTokenKeyApi loginTokenKeyApi)
    {
        _loginTokenKeyApi = loginTokenKeyApi;
    }

    public void SampleMethod()
    {
        // method logic goes here...
        var xx = _loginTokenKeyApi.WhatEver;
    }
}

然后在startup.cs中注册ILLoginTokenProvider和IMyClass

services.AddTransient<ILoginTokenProvider, LoginTokenProvider>();
services.AddTransient<IMyClass, MyClass>();

最后在你需要的地方注入 IMyClass:

public class IndexModel : PageModel {

    private readonly IMyClass _myClass;

    public IndexModel(IMyClass myClass)
    {
        _myClass = myClass;
    }

    public void OnGet()
    {
       _myClass.SampleMethod();
    }
}

顺便说一句,也可以在不实现 IMyClass 接口的情况下注册和注入 MyClass,但我更喜欢遵循基本的编程原则:)

【讨论】:

  • 您无需创建和实现接口即可正确使用依赖注入。切换到接口不会帮助 OP 实现他们想要实现的目标,即使用 new 创建一个对象,同时自动解决依赖关系。这不适用于依赖注入。
  • @poke,我已经提到,创建接口对于 DI 来说不是必需的,但是问题本身并不足以解释问题,所以我试图提供一个可能的解决方案。
【解决方案3】:

有两种类型的依赖注入。

  1. 构造函数注入 - 你不想要的
  2. Property Injection - 在此 - 您公开要注入的 Object 的 Public Get/Set 属性。然后在您的 DI 配置文件(如 spring.net)中,您可以分配值。

您可以进行 DepInjection 的另一种方法是在无参数构造函数中 - 您可以通过键/名称获取对象。就像在 Spring.Net 中一样,我们会这样做:

var UtilityObject = Spring.ContextRegistry.GetContext().GetObject("MyUtilObject") as TheUtilityClass;

【讨论】:

  • 不是我的反对意见,但此答案并未涵盖 OP 在尝试使用依赖注入时遇到的基本问题。属性注入根本无法解决这个问题,即使使用属性注入,您也将能够new 一个对象(这是 OP 想要做的)。
  • @poke - 我们的答案/帖子是针对 OP 发布的问题的第一个版本。问题已修改。此外,OP 可以删除构造函数注入(添加 Param Less 构造函数)——这将允许他新建对象。此外,正如我建议的那样,他们可以添加 GetObject() 调用以获取依赖项。
猜你喜欢
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 2016-01-01
  • 1970-01-01
相关资源
最近更新 更多