【问题标题】:When using dependency injection in C#, why does calling an interface method automatically call the implemented class' method?在C#中使用依赖注入时,为什么调用接口方法会自动调用实现类的方法?
【发布时间】:2020-12-30 07:15:51
【问题描述】:

为了澄清我的问题,假设我有以下非常基本的统计接口和类:

public interface IStatistics
{
   void IncrementPacketsDiscovered();
}

public class Statistics : IStatistics
{
   private int numberOfPacketsDiscovered = 0;

   public void IncrementPacketsDiscovered()
   {
      numberOfPacketsDiscovered++;
   }
}

然后假设我有以下类接收注入的 IStatistics 对象:

public class Reporter
{
   private IStatistics _statistics;
       
   public Reporter(IStatistics statistics)
   {
      _statistics = statistics;
      _statistics.IncrementPacketsDiscovered();
   }
}

为什么我可以在 IStatistics 对象上调用 IStatistics 方法 IncrementPacketsDiscovered() 并且它自动知道要获取在 Statistics 类中实现的方法定义?

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 因为您在某处告诉 DI 容器 IStatistics 将被 Statistics 解析?所以DI容器看到IStatistics的请求,只返回一个Statistics对象
  • 看看你是如何注入它的,你做了这样的事情:services.AddTransient<IStatistics, Statistics>(); 所以它就是这样关联它的。
  • @CamiloTerevinto @Andy 啊,是的,你们两个都是对的。在我的主要方法中,我有:public static Statistics statistics = new Statistics();。我最终致电:services.AddSingleton<IStatistics>(statistics);。非常感谢您的帮助,真的为我澄清了一切:)

标签: c# dependency-injection interface


【解决方案1】:

TLDR;因为实现IStatistics 的注入对象是Statistics 类的一个实例,之所以这样是因为在其他地方你告诉依赖解析器在你提到IStatistics 时使用Statistics ..


请注意,Statistics.IncrementPacketsDiscovered 被调用与 DI 本身无关,您可以这样写:

IStatistics x = new Statistics();
x.IncrementPacketsDiscovered();

在外部,x 看起来像 IStatistics。在里面,它是一个Statistics。如果 Statistics 做了其他事情(不仅仅是实现接口),它会更容易看到。如果您有其他实现IStatistics 的东西,比如您在测试场景中使用的某种FakeStatistics,那么可能会更清楚发生了什么 - 测试是您将程序切换回来的有效理由之一在不同的对象套件之间来回切换。

您可以想象在您的所有代码之外的某个地方是依赖关系解析器,它是由 Microsoft* 创建的。它为你完成了上面的第一行代码,后来当你说你想要一个 Reporter 它看起来并看到“构造函数接受任何实现 IStatistics 的参数,而我恰好有一个Statistics 的实例在此处符合该要求,因此我会将其传递给 Reporter 构造函数..”,因为这是它被配置为执行的操作/这就是它的工作。

如果你有一个用于测试的 FakeStatistics,以及一个你重新配置注入器以创建和提供假对象的上下文,那么它突然开始变得有意义,为什么它是一种有用的工程方法 - 你不必有100 个你说new Statistics 的地方,你经过的地方全部改成new FakeStatistics。编写一个类并突然意识到“这个类需要统计信息..”也很有用,您向构造函数添加一个参数IStatistics x,点击 Ctrl . 并选择为其添加属性的选项,并且该类现在可以访问由解析器提供的IStatistics 的合适实现。你不必到处追查你说new MyXClass(param1, param2) 并将其更改为new MyXClass(param1, param2, someStatistics),因为new处理所有对象的工作是解析器的责任

通过使用接口和编码,“任何实现此接口的对象都可以明智地用作此类的输入参数”,然后您就可以打开“类实例查找和提供者服务”连接的可能性只需“在当前配置的对象包中翻找可以完成工作的对象”(然后根据上下文更改包中的内容)即可将所有应用程序放在一起

那么你把东西放在包里的什么地方了?在您配置解析器的程序部分中,AddScopedAddTransientAddSingleton 等方法具有双重目的,将类类型映射到接口类型,并配置实例的生命周期- 解析器为您管理实例,并在您指定的使用 Add* 方法的生命周期内创建/销毁它们

* 有了这个声明,我当然是在粗略地假设您使用的是哪种注射器。还有其他可用于 C# 的 DI/IoC 框架,由其他人创建。总体概念保持不变;你越能让计算机为你编写代码,它就越快、更容易和更可靠。在程序中建立对象之间的依赖关系就是这样一个地方,将其交给软件而不是自己编写是有意义的

【讨论】:

  • “微软创造的东西”...假设 .NET Core 的 DI 太多了? :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 2020-06-07
相关资源
最近更新 更多