2010-07-02 60 views
4

在某些情况下,有人会将接口作为参数传递(或接收)接口?这真的是一个有用的东西,或者只是一个奇特的做事方式?作为参数的接口

+0

我对C#很新,所以有些答案超出了我的头。:-)对不起,但只是试图构建我的基本概念。 根据你的答案和我已经读过的关于接口的内容,我简单地说,通过将接口作为参数传递,我们允许我们可以将任何(只有那些)对象传递给方法实现该接口。就像下面的例子(IAnimal),我们可以将任何动物传递给MakeNoise方法,只要它实现了IAnimal。 – 2010-07-02 15:16:09

+0

是的,一个接口基本上代表了由一个类实现的一组功能。当你编写你的方法来接受一个接口作为参数时,这意味着该方法将接受任何实现该接口的类型的对象。在'IAnimal'例子中,'IAnimal'接口保证了一个名为'MakeNoise'的方法,所以接受一个'IAnimal'作为参数的方法可以在该参数上调用'MakeNoise',而不管它的基础类型如何。 – 2010-07-02 15:21:20

+0

谢谢丹。现在很清楚。 – 2010-07-02 15:24:05

回答

18

这是一个有用的东西极其。例如

任何LINQ extension methods。他们不在意传递给他们的东西,只要它实现了IEnumerable<T>。这个想法是,它们都可以应用于任何你可以使用循环来枚举的东西。

想象一下,如果他们都要求您通过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来枚举它;但因为我已经输入valuesList<double>,传递一个double[]Sum方法我不得不这样做:

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

这只是我已经构造简单地调用代码,真的完全没有必要的新对象应该能够首先处理我的原始对象。

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

+1

+1对**非常有用** – cjk 2010-07-02 14:39:41

2

每当你需要抽象时。

一个很好的例子是.NET Framework中的接口IEnumerable<T>IQueryable<T>。他们允许你写扩展方法,可用于对抗List<T>,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但我们认为合适用于测试目的。通常这涉及具有指定行为的简单模拟对象以产生可靠的结果。

1

接口非常有用。

他们帮助解耦你的代码 - 例如,如果你使用的IList接口,并把它传递给你的方法和你的方法使用它,你可以在任何集合实现此接口传递,无论是在BCL或没有。

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

接口编程是面向对象的一个​​核心方面,你会发现它们非常有用。

+0

+1非常容易理解的解释。谢谢。 – 2010-07-02 15:26:03

+0

因为你只编程到界面,请仔细选择他们的名字。在这种情况下,INoiseMaker可能更合适。这样,其他类就可以实现接口,比如JetPlane,FireCracker或SmallChild。 – 2010-07-02 15:26:53

+0

@Dave M,很好的一点,界面(合同)应该描述他们的使用。谢谢 :) – 2010-07-02 15:28:45

0

多态性!

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