Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.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#_Oop_Interface_Design Patterns - Fatal编程技术网

在C#中使用接口有哪些优点?

在C#中使用接口有哪些优点?,c#,oop,interface,design-patterns,C#,Oop,Interface,Design Patterns,几年前,我被迫在工作中从事一个软件项目,被迫快速学习C#。我的编程背景很差(经典ASP) 这些年来我学到了很多,但由于我学习C#的强迫性,有很多基本概念我还不清楚 具体来说,是一个接口。我了解基础知识,但在编写应用程序时,我很难找出一个应用程序的实际用途。为什么要为应用程序编写接口 谢谢 凯文一个界面说明了某些东西应该如何工作。将其视为合同或模板。它是控制反转或依赖注入等事情的关键 我使用结构图作为IoC容器。这允许我为所有类定义一个接口。你可能会说 Widget w = new Widget(

几年前,我被迫在工作中从事一个软件项目,被迫快速学习C#。我的编程背景很差(经典ASP)

这些年来我学到了很多,但由于我学习C#的强迫性,有很多基本概念我还不清楚

具体来说,是一个接口。我了解基础知识,但在编写应用程序时,我很难找出一个应用程序的实际用途。为什么要为应用程序编写接口

谢谢
凯文

一个界面说明了某些东西应该如何工作。将其视为合同或模板。它是控制反转或依赖注入等事情的关键

我使用结构图作为IoC容器。这允许我为所有类定义一个接口。你可能会说

Widget w = new Widget();
我会说

IWidget w = ObjectFactory.GetInstance<IWidget>();
然后,当我通过StructureMap这样的方式新建一个小部件实例时

IWidget widget = ObjectFactory.GetInstance<IWidget>();
IWidget widget=ObjectFactory.GetInstance();
请注意,我没有在构造函数中指定存储库或服务。StructureMap通过构造函数中指定的接口知道如何获取适当的实例并将它们传递进来。这使得代码非常强大和干净

所有这些都来自接口的简单定义和它们的一些巧妙使用

好文章

接口是一种契约,它向客户机保证类或结构的行为

这可能是我遇到的最清楚最简单的解释方式:

“答案是,它们提供了一种相当类型安全的方法,可以在您不知道将提前传递的对象的特定类型时构建接受对象的例程。关于将传递给例程的对象,您所知道的唯一一件事是,它们具有特定的成员,这些成员必须存在,以便例程能够使用该对象。 我能给出的关于接口需求的最好例子是在团队环境中。接口有助于定义不同组件之间的通信方式。通过使用接口,可以消除开发人员误解必须添加到类型中的成员或如何调用定义接口的其他类型的可能性。如果没有接口,错误会潜入系统,直到运行时才显示出来,因为很难找到错误。有了接口,定义类型时的错误会在编译时立即被捕获,而代价要小得多。”

基本情况是“IWriter”情况

假设您正在创建一个可以写入控制台的类,它具有各种有用的函数,如write()和peek()

然后,您希望编写一个可以写入打印机的类,因此,您可以使用IWriter接口,而不是重新创建一个新类


现在关于接口最酷的一点是,您可以编写所有的编写代码,而事先不知道编写目标是什么,然后在用户决定时(在运行时)可以无论他是想写入控制台还是打印机,您只需将对象定义为控制台/打印机写入器,无需更改写入代码中的任何内容,因为它们都使用相同的前端(接口).

这是一个关于接口的概念。它推广了接口属于客户端的概念,也就是说,属于调用方。这是一个很好的概念。如果您只需要调用的东西来实现-say-count()和get()你可以定义这样的接口,让类实现这些函数。一些类会有很多其他的函数,但是你只对这两个函数感兴趣,所以你需要知道你正在使用的类。只要它们满足了契约,你就可以使用它们。报告,基本上有两种不同的报告类型。一种是图表,一种是表格。我需要将这些报告保存为PDF格式,并将它们发送给其他人。 用户单击以将报告保存为PDF的菜单的事件处理程序可以执行以下操作:

void ExportPDF_Clicked(...) {
   if(currentDocument is ChartReport) {
      ChartReport r = currentDocument as ChartReport;
      r.SavePDF();
   } else if(currentDocument is GridReport) {
     GridReport r = currentDocument as GridReport;
      r.SavePDF();
   }
}
我宁愿让我的ChartReport和GridReport实现以下接口:

public interface Report {
  void MailTo();
  void SavePDF();
}
现在我可以做:

void ExportPDF_Clicked(...) {
   Report r = currentDocument as Report;
   r.SavePDF();
}
对于需要在不同报告类型上执行相同操作(保存到文件、放大、打印等)的其他代码,情况类似。
当我在下周添加数据透视表报表时,上面的代码仍然可以正常工作。

上面已经提到了IOC和依赖项注入,我希望您看看它们

然而,在很大程度上,接口允许为不需要继承模型的对象指定约定

假设我有一个类Foo,它有函数x和y以及属性z,我围绕它构建代码

如果我发现了一种更好的方法来进行Foo,或者其他类型的Foo需要实现,我当然可以将一个基本Foo类扩展到FooA、FooB、MyFoo等,但是这需要所有Foo都具有相同的核心功能,或者任何未来的Foo创建者都可以访问基本Foo类并了解其内部工作#,这意味着未来的Foo只能从Foo继承,因为C#不支持多重继承

它还要求我了解Foo未来可能的状态,并尽量不要在我的基本Foo类中禁止它们

使用接口IFoo只是说明类在我的Foo框架中工作所需的“契约”,我不关心任何未来的Foo类可能从中继承什么或在内部看起来是什么,只要它们有fn x fn y和z。它使框架更加灵活,并对未来的添加开放


但是,如果Foo需要大量的核心才能工作,而这些核心在契约场景中不适用,那么您会倾向于继承。

一个简单的答案是:使用接口根据契约而不是实现进行编程
void ExportPDF_Clicked(...) {
   Report r = currentDocument as Report;
   r.SavePDF();
}
public interface IServices
{
    DataManager Data { get; set; }
    LogManager Log { get; set; }
    SomeOtherManager SomeOther { get; set; }
}

public class MrPlugin
{
    public void Init(IServices services)
    {
        // Do stuff with services
    }
}