调用接口方法如何在C#中自动调用派生类方法?
给出了下面的依赖项反转的pluralsight示例,我对它是如何工作的感到非常困惑。因此,我们得到了以下接口和派生类实现调用接口方法如何在C#中自动调用派生类方法?,c#,dependency-injection,interface,C#,Dependency Injection,Interface,给出了下面的依赖项反转的pluralsight示例,我对它是如何工作的感到非常困惑。因此,我们得到了以下接口和派生类实现 public interface INotifyCustomer { void NotifyCustomer(Cart cart); } public class NotifyCustomerService : INotifyCustomer { public void NotifyCustomer(Cart cart) { stri
public interface INotifyCustomer
{
void NotifyCustomer(Cart cart);
}
public class NotifyCustomerService : INotifyCustomer
{
public void NotifyCustomer(Cart cart)
{
string customerEmail = cart.CustomerEmail;
if (!String.IsNullOrEmpty(customerEmail))
{
using (var message = new MailMessage("orders@somewhere.com", customerEmail))
using (var client = new SmtpClient("localhost"))
{
message.Subject = "Your order placed on " + DateTime.Now;
message.Body = "Your order details: \n " + cart;
try
{
client.Send(message);
}
catch (Exception ex)
{
Logger.Error("Problem sending notification email", ex);
throw;
}
}
}
}
}
我无法理解的一点是,简单地调用如下所示的接口会以某种方式调用派生类,而从未实例化或提及该派生类。示例如下:
public class Order
{
private readonly Cart cart;
private readonly PaymentDetails paymentDetails;
private readonly INotifyCustomer notifyCustomer;
public Order(Cart cart, PaymentDetails paymentDetails, INotifyCustomer notifyCustomer)
{
this.cart = cart;
this.paymentDetails = paymentDetails;
this.notifyCustomer = notifyCustomer;
}
public void Checkout(Cart cart, PaymentDetails paymentDetails, bool notify)
{
if (paymentDetails.PaymentMethod == PaymentMethod.CreditCard)
{
ChargeCard(paymentDetails, cart);
}
ReserveInventory(cart);
if (notify)
{
notifyCustomer.NotifyCustomer(cart);
}
}
}
谁能帮我解释一下吗?我对C并不陌生,但使用它的时间不长,在过去的几年里我更喜欢java,我知道C和java之间有着根本的区别。但我看不出这是如何工作的,也看不出为什么工作的?您的接口实现是一个契约。它只是说,“如果你实现了我(接口),那么你必须提供这个方法
NotifyCustomer
,它使用Cart
,并且不返回值(即void
)。如果你实现了它,你可以在NotifyCustomer
方法中做任何你想做的事情,只要你完成了上述操作
您的类
Order
不知道什么是notifyCustomer
,只知道它实现了INotifyCustomer
。但是,您的编译器知道,因此当代码编译和运行时,它实际上会在NotifyCustomerService
中调用您的代码。通过使用依赖项注入,您可以设计代码,而不必关心或不知道只要依赖项满足约定,就可以定义它们是如何实现的。实际上,类中的Order
中没有任何东西实例化NotifyCustomerService
,但它知道类型为INotifyCustomer
的对象有一个具有指定参数和返回类型的NotifyCustomer方法。它不必知道关于该方法在类NotifyCustomerService中的实现方式,即使这个问题没有明确的“答案”(可能范围太广),我还是想发布一个答案,希望能帮助巩固依赖注入的概念
考虑这一点:
从现在起,您编写的每一段代码都将只引用对象的抽象。抽象意味着接口(或者潜在的抽象类或基类,但这超出了我目前的观点)
这样做的好处是,您的代码不关心抽象是如何实现的,它所知道或关心的只是它期望存在的方法或属性
这为您提供了多种好处:
- 您的代码变得更加模块化,因为您可以通过注入不同的依赖项轻松地交换具体的实现
- 您可以让“Mock”类与实际类一致(想想API服务,您需要担心HTTP连接,现在您可以通过在Mock服务中伪造HTTP请求来单元测试其他代码)
- 等等等等
我想让你困惑的部分是你所理解的依赖注入的“魔力”。你的构造函数有一个
INotifyCustomer
类型的参数。当你的Order
类被实例化时,这些参数必须提供(是的,我知道在技术上可以传递null).由于我们已经确定您的代码对传入的内容绝对无关,只要其类型为INotifyCustomer
,您的代码就会像直接传入具体内容一样运行(但现在我们已经获得了依赖注入的所有好处).您缺少依赖项注入的注入部分。在构造函数中,您将传入具体的类实例(或者更好地使用IOC容器来完成)在某个地方,创建了一个NotifyCustomerService
,因为它实现了接口,所以显示的代码只关心传递的对象是否具有它想要调用的函数(没有神奇的转发:传递的对象实现了方法).@maccettura是正确的。虽然您将INotifyCustomer作为Order构造函数中第三个参数的类型,但只有实现INotifyCustomer的对象才能作为该参数提供。在这种情况下,必须为该对象的NotifyCustomer方法定义,因为接口需要它。我想我仍然感到困惑因为@maccettura注入实际上就在那里,通过构造函数注入INotificationService,他们稍后会在Checkout方法中调用它。这也是pluralsight的源代码,我写这段代码并不是只是想绕着它转。crashmstr你肯定是对的,因为代码是有效的,但在哪里呢NotifyCustomerService正在创建吗?当InotifymentService调用其NotifyCustomer方法时?它是否意识到实现的方法在派生类中?我知道注入在那里,我只是说您缺少注入的概念。它工作的原因是,必须使用的实例调用构造函数<代码>INotifyCustomer(我猜在技术上是空的)。编译器不知道实际实现是什么。运行时会知道。模式的全部要点是编译器不知道。也就是说,您还没有回答所问的问题,即实际运行时对象如何链接到显示的代码。编译器知道何时编译,除非reflection正在被使用,例如与IoC容器一起使用。不过,编译器当然可以知道。我已经回答了这个问题(它刚刚被接受)。这是我一直在寻找的答案。我没有意识到通过使用依赖项注入方法可以这样设置。我确信这在Java中是可能的,我从未见过它。虚拟分派的全部要点是编译器不知道。它不知道。它知道将有一个有效的I