2014-03-12 45 views
3

我在C#相當新的(我從爪哇來到),我有一個關於使用疑問:有關C#中IEnumerable接口的一些說明?

我有這個類:

namespace DataModel.MaliciousCode 
{ 

    public class PagedMalicious : Shared.Paged 
    { 
     public IEnumerable<MaliciousSmall> MaliciousCode { get; set; } 

    } 
} 

正如你可以看到這個類僅包含a IEnumerable<MaliciousSmall> MaliciousCode

閱讀在線文檔,在我看來,明白IEnumerable是一個接口,它給了我一個非泛型集合的迭代器。

究竟是什麼意思是以前的斷言?

MaliciousSmall這是一個模型對象的類型,在我的應用

所以我的疑問是:(包含一些屬性上的數據庫表的字段映射對象):

  • IEnumerable<MaliciousSmall> MaliciousCode:MaliciousCode是惡意小型對象的迭代集合?所以這意味着它代表一個集合和一些提供的方法來迭代它呢?

  • 如果以前的說法是真實的,OK MaliciousCode對象是一個迭代的集合,但IEnumerable的是一個界面,誰落實,反覆這個集合的方法(從Java未來我認爲這是不提供的接口的實施方法)

有人能幫助我理解這些東西嗎?

TNX

安德烈

+7

'IEnumerable的'是完全等同於Java的'可迭代'。 – SLaks

回答

4

IEnumerable<MaliciousSmall> MaliciousCodeMaliciousCodeMaliciousSmall對象的迭代集合?所以這意味着它代表一個集合和一些提供的方法來迭代它呢?

排序的 - IEnumerable<T>提供一種方法 - GetEnumerator - 它返回一個IEnumerator<T>這個接口允許你遍歷集合。 Pre-Linq全部IEnumerable允許你做的是使用foreach循環中的集合(或直接使用提供的IEnumerator,這很少見)。此後,Linq在IEumerable<T>上定義了擴展方法,允許更復雜的查詢如SelectWhere,Count等。

如果以前的說法是真實的,OK MaliciousCode對象是一個迭代的集合,但IEnumerable是一個界面,誰落實,反覆這個集合的方法(從Java未來我認爲,接口沒有提供實現的方法)

通常通過使用基本集合類型如List<MaliciousSmall>MaliciousSmall[]來提供實現。所以IEnumerable實現由該類提供。 C#2.0中引入的yield關鍵字允許您「返回」IEnumerable<T>並讓編譯器提供實際的實現。

所以在你的類,你可能內部實現集合爲List<T>

public class PagedMalicious : Shared.Paged 
{ 
    public IEnumerable<MaliciousSmall> MaliciousCode { get; set; } 

    public PagedMalicious() 
    { 
     MaliciousCode = new List<MaliciousSmall>(); 
    } 

    // other private methods that add to MaliciousCode 
} 

採用IEnumerable<T>允許您更改內部實現不改變公共接口。

+0

+1用於說明接口的內部實現。好答案! –

+0

從語言的角度來看,LINQ並沒有真正改變「IEnumerable」的功能。你只是調用helper方法,在後臺,只是迭代序列並對它進行處理。在LINQ之前,有很多方法需要一個'IEnumerable'並做一些有用的工作,而且之後還有很多方法。 LINQ是非常有用,廣泛使用和相當通用的方法,但這些方法都沒有改變語言對IEnumerable可以執行的基本功能。 – Servy

+0

@Servy你是對的,這就是爲什麼我明確表示他們是_extension methods_。雖然方便,但是語法擴展方法允許導致這個非常混亂,以至於接口明確提供了什麼以及擴展方法提供了什麼。 –

0

要你的疑惑: 是和是 接口本身不能實現任何東西,但你可以指定MaliciousSmall數組或List <MaliciousSmall>。他們都實現IEnumerable <MaliciousSmall>

1

您的財產MaliciousCode,代表實現IEnumerable<T>接口的類的對象。就其本身而言,IEnumerable並不意味着什麼。它只是提供了一個結構。用戶有責任以任何合適的方式實現與接口一起提供的方法。

編輯:這是一個簡單的例子來說明:

private void Form3_Load(object sender, EventArgs e) 
    { 
     Parent parent = new Parent(); 
     parent.Child = new List<Child>(); // -> this is where implementer is decided. 
     //Before this line, Child property is not instantiated and is not referring to any object. 
    } 

    public class Parent 
    { 
     public IEnumerable<Child> Child { get; set; } 
    } 

    public class Child 
    { 
     public int MyProperty { get; set; } 
    } 
+0

好的,但在這個特定的情況下,實現IEnumerable接口的類是什麼? – AndreaNobili

+0

@AndreaNobili - 你能用Java回答同樣的問題嗎? - 不,對於C#也是如此:看着界面,沒有辦法知道什麼類會實現它。你可以說一個類實現了這個接口(比如'List 'implements IEnumerable '),但是在這種特殊情況下使用'List'沒有辦法。 –

+0

更新了響應。 – danish

0

IEnumerable<T>是Java的Iterable<T>的等價物。由於早期版本的C#沒有泛型,IEnumerable是當時唯一可用的迭代器。你可以認爲它是一種IEnumerable<object>

大多數通用收集類型實現了IEnumerable<T>,包括數組。通用變體需要實現非通用變體,因此大多數集合(通用或不通用)都實現IEnumerable

但是,這些迭代器不限於表示集合。他們提供的方法允許枚舉項目,這些方法也可以算法生成項目。例如,理論上 - 可以通過枚舉提供無限枚舉方形數字,而不需要在任何地方存儲這些數字。

在你的情況下,IEnumerable<MaliciousSmall> MaliciousCode屬性可能會產生MaliciousSmall對象從數據庫一枚接一枚作爲枚舉枚舉,而不先存儲在一個集合對象中。

實施IEnumerable<T>您自己需要執行IEnumerator<T> GetEnumerator()方法。它返回一個枚舉器對象,它需要實現方法bool MoveNext(),void Dispose(),void Reset()和屬性T Current { get; }

你可以通過編寫很多代碼來實現這些接口,也可以使用C#的迭代器。迭代器使用大量的編譯器魔法在幕後自動創建枚舉數和枚舉數。參見:Iterators (C# and Visual Basic)


以C#迭代的例子,讓我們實現您與他們的例子(我放棄了二傳,因爲它代表的方式在這裏):

public class PagedMalicious : Shared.Paged 
{ 
    public IEnumerable<MaliciousSmall> MaliciousCode 
    { 
     get 
     { 
      using (var conn = new SqlConnection("<my server connection>")) { 
       var cmd = new SqlCommand("SELECT name, number FROM myTable", conn); 
       conn.Open(); 
       using (var reader = cmd.ExecuteReader()) { 
        while (reader.Read()) { 
         var maliciousSmall = new MaliciousSmall { 
          Name = reader.GetString(0), 
          Number = reader.GetInt32(1) 
         }; 
         yield return maliciousSmall; 
        } 
       } 
      } 
     } 
    } 
} 

每次執行yield return,控制是傳回給呼叫者,他得到下一個項目。 getter方法的狀態保持不變,其執行在此停止,直到調用者繼續迭代並需要下一個項目。當他這樣做時,執行會在yield return聲明之後重新開始。

從這個例子可以看出,枚舉是以懶惰的方式評估的。以下代碼總結了整個表格的編號。這些項目永遠不會存儲在一個集合中;它們從數據庫中檢索並在枚舉時創建。這是一個優點,如果你有一百萬條記錄! (你可以使用一個SQL SUM聚合函數在生產一段代碼,就這樣。)

var pagedMalicious = new PagedMalicious(); 
int sum = 0; 
foreach (MaliciousSmall item in pagedMalicious.MaliciousCode) { 
    sum += item.Number; 
}