接口作为参数

时间:2010-07-02 14:21:03

标签: c# interface

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

6 个答案:

答案 0 :(得分:18)

这是非常有用的东西。

例如, LINQ extension methods 。他们不关心传递给他们的是什么,只要它实现IEnumerable<T>。我们的想法是,它们都可以应用于您可以使用foreach循环枚举的任何内容。

想象一下,如果他们都要求你传递T[]数组或List<T>个对象,那将是多么无谓的限制。


这只是一个非常简单的例子。让我们假装LINQ扩展不存在(如果我使用的是.NET 2.0,这实际上是可能的)并且我想写一个Sum方法。

我可以这样写:

public static double Sum(List<double> values)
{
    double sum = 0.0;
    foreach (double value in values)
    {
        sum += value;
    }
    return sum;
}

这一切都很好,但在这里注意一些事情:我写了一个方法来获取List<double>,这是一个具有功能远远超过此代码所依赖的的类。它在哪里使用Insert?它在哪里使用RemoveAtFindAllSort?不,这不是必需的。那么这个方法是否真的必要才能传递List<double>

此外,我说有double[]。从理论上讲,我应该可以在values参数中弹出它,因为我所做的只是使用foreach枚举它;但由于我已将values键入为List<double>,要将double[]传递给Sum方法,我必须执行此操作:

double sum = Sum(new List<double>(myArray));

这只是一个完全不必要的新对象,我构建它只是为了调用那些本来应该能够处理原始对象的代码。

通过编写将接口作为参数的方法,您可以使代码更灵活,更强大,并且避免施加不适当的限制(给我一个X,即使我可以很容易地用Y < / em>)关于调用代码。

答案 1 :(得分:5)

最容易记住的方法是,它是关于接口编程而不是实现。比方说,我有一个方法,我想做点什么,例如。

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");
  }
}

接口编程是OOP的核心方面,你会发现它们非常有用。

答案 2 :(得分:2)

每当你需要抽象时。

一个很好的例子是.NET Framework中的IEnumerable<T>IQueryable<T>接口。它们允许您编写可用于List<T&gt;,Dictionary<TKey, TValue>甚至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,但我们认为适合测试目的。通常,这涉及一个具有指定行为的简单模拟对象,以产生可靠的结果。

答案 3 :(得分:1)

接口非常有用。

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

答案 4 :(得分:1)

如果您使用的是design pattern approach,那么界面非常有意义的一个领域。

例如,Observer patternProxy patternVisitor pattern等。您可能可以选择不使用接口,但我想你会很快决定代码变得更清晰(如更模块化,关注点分离)而不是非接口代码。在这些情况下,它只是有助于促进更好的代码。

答案 5 :(得分:0)

多态性!

它们可以帮助您编写不区分某些类的代码,因为它们不会从特殊的基类继承。您的职能将是平等机会执行者。