简体   繁体   English

在C#中使用依赖注入时,为什么调用接口方法会自动调用实现类的方法?

[英]When using dependency injection in C#, why does calling an interface method automatically call the implemented class' method?

To clarify my question, suppose I have the following very basic statistics interface and class:为了澄清我的问题,假设我有以下非常基本的统计接口和类:

public interface IStatistics
{
   void IncrementPacketsDiscovered();
}

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

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

Then suppose I have the following class that receives the injected IStatistics object:然后假设我有以下接收注入的 IStatistics 对象的类:

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

Why is it that I am able to call the IStatistics method IncrementPacketsDiscovered() on the IStatistics object and it automatically knows to fetch the method definition that was implemented in the Statistics class?为什么我能够在 IStatistics 对象上调用 IStatistics 方法 IncrementPacketsDiscovered() 并且它自动知道获取在 Statistics 类中实现的方法定义?

Any help would be greatly appreciated.任何帮助将不胜感激。 Thank you!谢谢!

TLDR; TLDR; because the injected object that implements IStatistics is an instance of the Statistics class, and it is this way because somewhere else you told the dependency resolver to use Statistics whenever you mention IStatistics ..因为实现IStatistics的注入对象是Statistics类的一个实例,这是因为在其他地方你告诉依赖解析器在你提到IStatistics时使用Statistics ..


Note that Statistics.IncrementPacketsDiscovered being called is nothing to do with DI per se, you could write this:请注意,调用Statistics.IncrementPacketsDiscovered与 DI 本身无关,您可以这样写:

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

On the outside, x looks like an IStatistics .在外面, x看起来像一个IStatistics On the inside, it is a Statistics .在里面,它是一个Statistics If Statistics did something else (other than just implement the interface) it would be easier to see.如果统计做了别的事情(除了实现接口),它会更容易看到。 It would also probably be more clear what's going on if you had something else that implemented IStatistics , like some sort of FakeStatistics that you use in a test scenario - testing is one such valid reason where you'd switch your program back and forth between different suites of objects.如果您有其他实现IStatistics东西,例如您在测试场景中使用的某种FakeStatistics ,那么可能会更清楚发生了什么 - 测试就是一个这样的正当理由,您可以在不同的程序之间来回切换对象套件。

You could just conceive that somewhere outside of all your code is the dependency resolver, a thing created by Microsoft*.您可以想象,在您的所有代码之外的某个地方是依赖解析器,它是由 Microsoft* 创建的。 It did that first line of code above for you, and later when you said you wanted to have a Reporter it looked and saw "the constructor takes a parameter of anything that implements IStatistic s, and I just happen to have an instance of Statistics here that fits that requirement, so I'll pass that into the Reporter constructor.." because that is what it is configured to do/that is its job.它为您完成了上面的第一行代码,后来当您说您想要一个Reporter它查看并看到“构造函数采用任何实现IStatistic的参数,而我恰好在这里有一个Statistics实例这符合该要求,所以我会将其传递给Reporter构造函数......”因为这就是它的配置/这就是它的工作。

If you had a FakeStatistics that you used for testing, and a context where you reconfigured the injector to create and supply fake objects then it suddenly starts to make sense why it's a useful way to engineer - you don't have to have 100 places where you said new Statistics where you go through and change them all to say new FakeStatistics .如果你有一个用于测试的 FakeStatistics,以及一个你重新配置注入器以创建和提供假对象的上下文,那么它突然开始变得有意义为什么它是一种有用的工程方式 - 你不必有 100 个地方你说的是new Statistics ,你在那里经过并将它们全部更改为new FakeStatistics It's also useful to be writing a class and suddenly realize "this class needs statistics.." you add a single argument IStatistics x to the constructor, hit Ctrl .编写一个类并突然意识到“这个类需要统计信息......”也很有用,你向构造函数添加了一个参数IStatistics x ,点击Ctrl and pick the option to add a property for it and that class now has access to a suitable implementation of IStatistics , supplied by the resolver.并选择为其添加属性的选项,该类现在可以访问由解析器提供的IStatistics的合适实现。 You don't have to chase up through everywhere you said new MyXClass(param1, param2) and change it to say new MyXClass(param1, param2, someStatistics) because the job of new ing all your objects is the responsibility of the resolver你不必在你说new MyXClass(param1, param2)所有地方追赶并将其更改为new MyXClass(param1, param2, someStatistics)因为new所有对象的工作是解析器的责任

By using interfaces and coding up such that "any object that implements this interface can sensibly be used as an input argument to this class" you then open it up to the possibility that a "class instance lookup and provider service" can wire all your app together just by "rummaging around in its currently configured bag of objects for one that will do the job" (and then you change what's in the bag depending on the context)通过使用接口和编码,“实现该接口的任何对象都可以明智地用作此类的输入参数”,然后您将其打开为“类实例查找和提供者服务”可以连接所有应用程序的可能性一起只是通过“在其当前配置的对象包中翻找一个可以完成工作的对象”(然后根据上下文更改包中的内容)

So where did you put things in the bag?那么你把东西放在包里的什么地方呢? In the part of the program where you configured the resolver, methods like AddScoped , AddTransient , AddSingleton have the dual purpose of mapping a type of class to a type of interface and also configure what sort of lifetime the instance has- resolvers manage instances for you and create/destroy them over the lifetime you specify by which Add* method you use在您配置解析器的程序部分中,像AddScopedAddTransientAddSingleton这样的方法具有双重目的,将类类型映射到接口类型,并配置实例具有的生命周期类型 - 解析器为您管理实例并在您指定使用的 Add* 方法的生命周期内创建/销毁它们

* With this statement I am, of course, making a gross assumption as to which injector you're using. * 有了这个声明,我当然是对您使用的喷油器做出粗略的假设。 There are other DI/IoC frameworks available for C#, created by others.还有其他可用于 C# 的 DI/IoC 框架,由其他人创建。 The overarching concept remains the same;总体概念保持不变; the more you can get the computer to write your code for you, the quicker, easier and more reliable it can be.让计算机为您编写代码的次数越多,它就会越快、越容易、越可靠。 Establishing dependenceies between objects in your program is one such place where it can make sense to hand it off to software rather than writing it yourself在程序中的对象之间建立依赖关系是将它交给软件而不是自己编写的一个地方

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过使用依赖注入的构造函数通过反射调用 c# class 方法 - call c# class method by reflection with constructor using dependency injection 通过由基类c#实现的接口调用类的方法 - Calling a method of a class through the interface implemented by the base class c# C#:为什么调用实现的接口方法对于类变量比对接口变量更快? - C#: Why calling implemented interface method is faster for class variable than for interface variable? 如何调用在接口中定义并在C#中的类中实现的方法? - How to call a method defined in interface and implemented in class in C#? 为什么在类中实现的C#接口方法必须是公共的? - Why must an C# interface method implemented in a class be public? 使用依赖注入在 class 中调用方法 - Call method in class using dependency injection 防止在派生类C#中调用基类实现的接口方法 - Prevent calling base class implemented interface method in the derived class C# C#调用抽象接口实现中的未实现方法 - C# calling un-implemented method in abstract interface implementation 仅当在 C# 中实现时才在接口实现上调用泛型方法 - Call generic method on interface implementation only if implemented in C# C# 调用class内部的接口方法 - C# call interface method within class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM