2010-07-02 149 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

多態性!

它們可以幫助您編寫不會因爲不從特定基類繼承而對某些類進行區分的代碼。你的職能將是平等機會的執行者。