Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
调用接口方法如何在C#中自动调用派生类方法?_C#_Dependency Injection_Interface - Fatal编程技术网

调用接口方法如何在C#中自动调用派生类方法?

调用接口方法如何在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

给出了下面的依赖项反转的pluralsight示例,我对它是如何工作的感到非常困惑。因此,我们得到了以下接口和派生类实现

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