C# 作为参数的接口

C# 作为参数的接口,c#,interface,C#,Interface,在什么情况下,有人会传递(或接收)接口作为参数?这真的是一件有用的事情还是仅仅是一种奇特的做事方式?每当你需要抽象的时候 一个很好的例子是.NET框架中的IEnumerable和IQueryable接口。它们允许您编写可用于列表、字典、甚至T[]的扩展方法 您还可以以依赖项注入为例。在ASP.NET MVC中,通常使用存储库进行数据访问: public class MyClassRepository { public MyClass GetById(int id) {

在什么情况下,有人会传递(或接收)接口作为参数?这真的是一件有用的事情还是仅仅是一种奇特的做事方式?

每当你需要抽象的时候

一个很好的例子是.NET框架中的
IEnumerable
IQueryable
接口。它们允许您编写可用于
列表、
字典
、甚至
T[]
的扩展方法

您还可以以依赖项注入为例。在ASP.NET MVC中,通常使用存储库进行数据访问:

public class MyClassRepository
{
    public MyClass GetById(int id)
    {
        // Some Implementation
    }
}

public class MyController
{
    private MyClassRepository _repo;

    public class MyController() : base(new MyClassRepository()) { }

    public class MyController(MyClassRepository repo) { _repo = repo; }
}
现在,如果你想模拟存储库进行单元测试,那你就完了。没有简单的办法。接口进来了

public interface IMyClassRepository
{
    public MyClass GetById(int id);
}

public class MyClassRepository : IMyClassRepository
{
    public MyClass GetById(int id)
    {
        // Some Implementation
    }
}

public class MyController
{
    private IMyClassRepository _repo;

    public class MyController() : base(new MyClassRepository()) { }

    public class MyController(IMyClassRepository repo) { _repo = repo; }
}

现在,随着接口的引入,我们可以自由地模拟IMyClassRepository,但是我们认为它适合于测试目的。通常这涉及一个具有指定行为的简单模拟对象,以产生可靠的结果。

接口非常有用


它们有助于解耦代码—例如,如果使用IList接口并将其传递给方法并在方法中使用,则可以传递实现此接口的任何集合,无论它是否在BCL中。

这是一件非常有用的事情

以任何一种为例。他们不在乎传递给他们的是什么,只要它实现了
IEnumerable
。其思想是,它们都可以应用于任何可以使用
foreach
循环枚举的对象

想象一下,如果它们都要求您传递
T[]
数组,或者
List
对象,那么这将是多么毫无意义的限制


这里只有一个非常琐碎的例子。让我们假设LINQ扩展不存在(如果我使用.NET2.0,这实际上是一种可能性),我想编写一个
Sum
方法

我可以这样写:

public static double Sum(List<double> values)
{
    double sum = 0.0;
    foreach (double value in values)
    {
        sum += value;
    }
    return sum;
}
这只是一个完全不必要的新对象,我构建它只是为了调用一开始就应该能够处理原始对象的代码


通过编写将接口作为参数的方法,您可以使代码更加灵活和强大,并且可以避免对调用代码施加不适当的限制(给我一个X,尽管我可以用Y轻松做到这一点)


例如,the,或the,the和其他。您可能可以选择不使用接口,但我可以想象,您会很快决定代码比非接口代码更干净(如在更模块化、关注点分离的情况下)。在这些情况下,它只会帮助提升更好的代码。

记住最简单的方法是,它是针对接口编程,而不是实现。比如说,我有一个我想做某事的方法,例如

public void MakeNoise(IAnimal animal)
{
  animal.MakeNoise();
}
我不在乎具体的实现是什么,我只知道无论传入什么,我都可以调用MakeNoise()。我把程序设计成一个接口,而不是一个实现

public class Dog : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Woof");
  }
}

public class Cat : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Meow");
  }
}
接口编程是面向对象编程的一个核心方面,你会发现它们非常有用。

多态性


它们帮助您编写的代码不会因为某些类不是从特殊基类继承而歧视它们。你的职能将是平等机会的执行者。

我对C#很陌生,所以有些答案超出了我的理解。:-)很抱歉,我只是想建立我的基本概念。根据您的回答,并根据我所读到的关于接口的内容,我简单地说,通过将接口作为参数传递,我们允许将任何(且仅那些)对象传递给实现该接口的方法,这是否正确。就像下面的例子(IAnimal)一样,我们可以将任何动物传递给MakeNoise方法,只要它实现了IAnimal。当您编写方法以接受接口作为参数时,这意味着该方法将接受实现该接口的任何类型的对象。在
IAnimal
示例中,
IAnimal
接口保证了一个名为
MakeNoise
的方法,因此,接受
IAnimal
作为参数的方法可以对该参数调用
MakeNoise
,而不管其底层类型如何。因为您只对接口编程,所以请仔细选择它们的名称。在这种情况下,INoiseMaker可能更合适。这样,其他类(如JetPlane、FireCracker或SmallChild)实现接口是很自然的。@Dave M,很好的一点,接口(契约)应该描述它们的使用。谢谢:)
public class Dog : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Woof");
  }
}

public class Cat : IAnimal
{
  public void MakeNoise()
  {
    Console.WriteLine("Meow");
  }
}