2009-10-07 61 views
2

我需要將不同的IEnumerables發送到Printer對象。 這個打印機對象然後會在foreach循環內對它們做些什麼。枚舉所有IEnumerable事件

class Printer 
{ 
    public Printer(IEnumerable list) 
    { 
     foreach (var enumerable in list) 
     { 
      //DO STUFF 
     } 
    } 
} 

這讓我發送任何枚舉,如List<T>到打印機的對象。 如

var list = new List<string> {"myList"}; 
    new Printer(list); //mylist 

這工作正常。 但如果我發送一個Dictionary<T, T>如:

var dictionary = new Dictionary<int, string> {{1, "mydict"}}; 
new Printer(dictionary); //[1, mydict] 

這將有一個鍵和一個值。我想要什麼,但將分開訪問foreach循環內的Value屬性。我所能訪問的是可枚舉對象,它沒有我可以使用的屬性。

現在如果數據類型T是包含多個屬性的對象(這適用於這兩個示例)。我如何能夠在我的foreach循環中使用這些屬性?

難道我真的要創建一個構造函數的重載,我可能發送給它的foreach可能的數據類型?

此外,我所需要做的所有foreach中的任何數據類型都不可靠 - 因爲它不會操縱所有內容。儘管如此,我確實需要訪問所有的屬性。

此外,這只是示例代碼,實際上並不是我在應用程序中使用的生產代碼。

+0

你不會在第一個例子中有同樣的問題嗎?畢竟你可以得到一個列表其中T是一個複雜的對象包含幾個屬性? – 2009-10-07 13:19:01

+0

你確定它接受IEnumerable而不是IEnumerable ? – 2009-10-07 13:19:41

+0

是的,這是我笨拙地試圖解釋在「現在怎麼辦」的段落。 我會嘗試編輯我的帖子,使其更清晰。 – CasperT 2009-10-07 13:20:15

回答

4

您可以更改打印機類的代碼嗎?如果它接受像IEnumerable<IPrintable>而不是僅僅IEnumerable那樣會更容易。有了這樣的接口:

interface IPrintable 
{ 
    void Print(); 
} 

然後將被髮送到Printer所有對象都需要實現該接口。然後,你可以這樣做:

class Printer 
{ 
    public Printer(IEnumerable<IPrintable> list) 
    { 
     foreach (var enumerable in list) 
     { 
      enumerable.Print(); 
     } 
    } 
} 

如果你有可打印對象的字典,是這樣的:

var dict = new Dictionary<int,IPrintable>(); 

你可以只值傳遞給函數:

var printer = new Printer(dict.Values); 
+0

這似乎是一個聰明的解決方案!我會讓線程生活幾個小時。如果沒有人勝過你的解決方案,我會接受你的回答 – CasperT 2009-10-07 13:33:07

2

如果你想以不同的方式處理不同的類型,你可能應該做出不同的方法。如果你想對待它們,你應該接受一個通用接口,並且只使用爲接口定義的方法。

這將有可能做

if (list is Dictionary<int, string>) { 
    // do special case 
} 

,但我一想到不寒而慄。

你甚至可以檢查一般:

class Printer<T> 
{ 
    public Printer<T>(IEnumerable list) 
    { 
     foreach (var enumerable in list) 
     { 
      if (list is Dictionary<T, T>) { 
       //DO STUFF 
      } 
     } 
    } 
} 
+0

我也不寒而慄 – CasperT 2009-10-07 13:21:59

+0

有無論如何檢查列表是否是字典? – CasperT 2009-10-07 13:24:44

+1

種類。看到我的補充。 – recursive 2009-10-07 13:35:08

1

的問題是一個集合,雖然它是枚舉,可以容納不同類型的對象,當你與ListDictionary之間的差別看到。

要避免這種情況,而不對每種對象類型進行編碼,只需接受您定義的某種類型的枚舉集合,例如IEnumerable<IMyType>

1

如果您無法在被叫方執行任何操作,因此主叫方應確保其通過對打印機「有效」的IEnumerable,例如通過dictionary.Values而不是在你的例子中是。但是,如果該類是公開的並且將被第三方用戶使用,則最好爲IEnumerable添加一些通用約束,如其他人所述。

3

在調用新的Printer()之前,您必須提取一個枚舉值和要傳遞的值。在字典的情況下,這很簡單:只需使用dict.Values即可。更普遍的情況是:

var list = List<MyObject>()... 

var printer = new Printer(list.Select(x => x.MyProperty)); 
4

您可以修改你的方法接受返回數據的打印方法需要一個委託。事情是這樣的:

// You will not need this class, if you always want a single string result. 
class PrinterData 
{ 
    public string Value { get; set; } 
    // More properties? 
} 
class Printer 
{ 
    public Printer<T>(IEnumerable<T> list, Func<T, PrinterData> func) 
    { 
     foreach (T item in list) 
     { 
      PrinterData data = func(item); 
      // Do something with the data. 
     } 
    } 
} 

用法:

int[] ints = new int[] {1,2,3}; 
new Printer().Print(ints, x => new PrinterData() { Value = x.ToString() }); 

var dictionary = new Dictionary<int, string> {{1, "mydict"}}; 
new Printer().Print(dictionary, x => new PrinterData() { Value = x.Name + " = " + x.Value }); 

每埃裏克斯滕達爾的回答很相似。

0

這是結果︰ 我用你們的幫助,所以我想我不應該投我自己的答案。

class Printer 
{ 
    public Printer(IEnumerable<IPrintable> list) //Accepts any collection with an object that implements IPrintable interface 
    { 
     foreach (var enumerable in list) //iterate through list of objects 
     { 
      foreach (var printable in enumerable)//loops through properties in current object 
      { 
       //DO STUFF 
      } 
     } 
    } 
} 

interface IPrintable : IEnumerable { } 
class SomeObject : IPrintable 
{ 
    public string Property1 { get; set; } 
    public string Property2 { get; set; } 

    public interface IEnumerable 
    { 
     IEnumerator GetEnumerator(); //Returns a Enumerator 
    } 

    public IEnumerator GetEnumerator() 
    { 
     yield return Property1; 
     yield return Property2; 
    } 
} 

我自然要實現自定義的GetEnumerator()的foreach對象 - 沒問題,但!

+0

儘管可以upvote :) – CasperT 2009-10-07 17:59:22