抽象类和依赖注入

时间:2021-05-11 02:34:04

标签: c# dependency-injection abstract-class

我想了解如何实现依赖注入,但我有一些问题:

  1. 我可以使用抽象类吗?我读了一些关于 DI 的文章,如果我理解得很好,他们说你必须使用接口而不是抽象类 - 如何避免在不同的类中使用重复的代码?

  2. 如果我在一个类中有很多依赖项,我是否必须在构造函数中注入所有这些依赖项?如果我没有在所有方法中都使用它们怎么办?

  3. 我可以实例化对象吗?如果我不实例化对象,我如何调用类的构造函数?

3 个答案:

答案 0 :(得分:4)

<块引用>

我可以使用抽象类吗?

是的。然而,在实践中,使用接口可能有一些优势。例如,有时在测试时模拟接口比抽象类更容易。我还会问你为什么觉得需要使用抽象类而不是接口,但这引出了下一点......

<块引用>

如何避免在不同的类中使用重复的代码?

一般来说,您应该 favor composition over inheritence 以实现代码重用。

<块引用>

如果我在一个类中有很多依赖项,我是否必须将它们全部注入到构造函数中?

不,还有其他方法可以注入依赖项,例如方法。但我会说构造函数注入是“经典”的 DI 模式,它有一些优点。例如,如果您在构造函数中注入所有依赖项,那么您无需担心在设置所需的依赖项之前有人在您的类上调用方法。

<块引用>

如果我不在所有方法中都使用它们怎么办?

这在小范围内是可以的。但是,如果您有很多依赖项或很多方法,这可能表明您的类做得太多了。如果您有不同的方法/依赖项组(例如,如果方法 A、B、C 使用依赖项 1、2,而方法 D、E、F 使用依赖项 3、4),则尤其如此。见Single Responsibility Principle

<块引用>

我可以实例化对象吗?如果我不实例化对象,我如何调用类的构造函数?

考虑不同类型的类很重要。您不需要将 DI 用于简单地保存数据的简单 POCO 类——您可以根据需要随意new。但是,DI 对于执行某些业务逻辑或与某些外部系统(如数据库)交互的服务类型类非常重要。在这种情况下,您不应该使用 new 在您的类中实例化它们。

当然,您必须在某个时候实例化这些对象。但是 DI 的重点是依赖于 X 的类不应该也实例化 X。依赖注入框架通常有一个“组合根”,所有依赖都在其中连接起来。您会在那里看到正在创建的新实例。

答案 1 :(得分:0)

简答:

  1. DI 只是一种允许在类之外创建依赖的模式。据我所知,您可以使用抽象类,具体取决于您如何导入容器。
  2. 您可以通过其他方法inject。 (构造函数在很多方面只是一种)。
  3. 您应该使用 lib 或imp 容器。通常,它们使用 decorator 来保存有关依赖项的描述,然后您使用它来创建实例。

答案 2 :(得分:0)

抽象类

<块引用>

1- 我可以使用抽象类吗?我读了一些关于 DI 的文章,如果我理解得很好,他们说你必须使用接口而不是抽象类,但是我如何避免在不同的类中使用重复的代码?

我认为你在谈论两件不同的事情。

A.您可以使用抽象类,而不必使用接口。这是一个例子。

internal abstract class BaseService
{
    public abstract string GetString();
}

internal class ServiceC : BaseService
{
    public override string GetString() => "ServiceB";
}

internal class ServiceD
{
    public ServiceD(BaseService baseService) { BaseService = baseService; }
    public BaseService BaseService { get; }

}

static void Main(string[] args)
{

    // ServiceCollection is package Microsoft.Extensions.DependencyInjection
    var serviceProvider = new ServiceCollection()
        .AddSingleton<BaseService, ServiceC>()
        .AddSingleton<ServiceD>()
        .BuildServiceProvider();

    var serviceC = serviceProvider.GetService<BaseService>(); 

    var serviceD = serviceProvider.GetService<ServiceD>();

    //serviceD.BaseService is ServiceC

B.即使您使用接口,您仍然可以使用抽象类,用于非 DI 部分。

请考虑以下示例。

internal abstract class BaseService { protected string GetCommon() => "Common functionality"; }

internal interface IServiceA { string GetA(); }

internal interface IServiceB { string GetB(); }


internal class ServiceA : BaseService, IServiceA
{
    public string GetA() => "A + " + GetCommon();
}

internal class ServiceB : BaseService, IServiceB
{
    public string GetB() => "B + " + GetCommon();
}

static void Main(string[] args)
{

    // ServiceCollection is package Microsoft.Extensions.DependencyInjection
    var serviceProvider = new ServiceCollection()
        .AddSingleton<IServiceA, ServiceA>()
        .AddSingleton<IServiceB, ServiceB>()
        .BuildServiceProvider();

    var serviceA = serviceProvider.GetService<IServiceA>();

    Console.WriteLine(serviceA.GetA()); // "A + Common functionality"

    Console.WriteLine(serviceProvider.GetService<IServiceB>().GetB()); // B + Common functionality

}

只有构造函数?

您可以在方法中使用额外的依赖项。

internal class ServiceE
{
    private readonly IServiceA a;

    public ServiceE(IServiceA a)
    {
        this.a = a;
    }

    public string AandB(IServiceB b) => a.GetA() + b.GetB();
}