2016-12-19 59 views
3

我有一個工廠函數,並且想用它來創建一個Enumerable。在C#中,我沒有找到一個直接的聲明方式來完成這項工作。所以我這樣做:使用工廠函數從發生器方法創建IEnumerable <>

public IEnumerable<Contact> Get() 
{ 
    return Enumerable.Range(1, 5).Select(x => GenerateRandomContact()); 
} 

有沒有更好的方法?

// Expected format 
public IEnumerable<Contact> Get() 
{ 
    return Enumerable.Generate(GenerateRandomContact).Take(5); 
} 
+0

你期待'Enumerable.Generate(GenerateRandomContact)'返回什麼?一個可產生無限數量隨機聯繫人的枚舉,希望有人在嘗試列舉整個枚舉之前在鏈中稍後調用限制函數(如「Take」)?這是可行的,儘管通常不應該如何使用Linq函數。 –

+0

我通常只是創建一個List <>對象,而不是生成自定義的IEnumerable類型。所以我只是使用ListrNumbers = Enumerable.Range(1,5).Select(x => GenerateRandomContact())。用你的代碼,任何人都可以知道只有5個數字被返回? – jdweng

+0

@jdweng:通過查看文檔(與您的方法相同)。或者調用['Count()'](https://msdn.microsoft.com/en-us/library/bb338038(v = vs.110).aspx)。 –

回答

4

喜歡的東西:

public static IEnumerable<T> Generate(Func<T> generator) 
{ 
    while(true) 
     yield return generator.Invoke(); 
} 

但你不能擴展靜態類。所以你應該把它放在助手類中。

+5

兩件事:首先,不應該這樣做'公共靜態IEnumerable 生成(函數生成器)'? '動作'只有一個'T'作爲輸入並且沒有輸出,而'Func '沒有輸入並且返回一個'T'作爲輸出。其次,雖然這是一種創建任意數量元素的簡單方法,但只有在沒有人**調用'ToList()'或者運行到'OutOfMemoryException'的情況下,這纔有效。 –

+0

'OutOfMemoryException'將在調用者的良心上。無限生成器在函數式編程風格中非常重要。 – DarkWanderer

+0

@ms感謝您解決而不是抱怨。 darkWanderer,你會如何限制結果?只是通過一個最大值? –

1
public IEnumerable<Contact> Get() 
{ 
    for(int i = 1; i <= 5; i ++) 
    { 
     yield return GenerateRandomContact(); 
    } 
} 

,或者如果你想有一個特定的金額,你可以做到這一點

public IEnumerable<Contact> Get(int number) 
{ 
    for(var i = 1; i <= number; i ++) //is the same as for (var i = 1;; i++) you got the idea 
    { 
     yield return GenerateRandomContact(); 
    } 
} 

你期待像Enumerable.Generate()

爲了得到你想要的元素列表枚舉,你的Generate方法應該返回一個Enumerable Value。您正試圖根據您的方法爲Enumerable創建擴展方法。在此之前,嘗試看看範圍

public static IEnumerable<int> Range(int start, int count) 
{ 
    long max = ((long)start) + count - 1; 
    if (count < 0 || max > Int32.MaxValue) throw Error.ArgumentOutOfRange("count"); 
      return RangeIterator(start, count); 
} 

static IEnumerable<int> RangeIterator(int start, int count) 
{ 
    for (int i = 0; i < count; i++) yield return start + i; 
} 

的實施與屈服這種情況下,.NET爲您創建了IEnumerable類和基於特定量。也許你應該考慮通過對生成方法的金額,或像其他擴展爲Concat的,你應該通過了IEnumerable,參見下文如何傳遞給聯繫mehotd了IEnumerable第一可變

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) 
{ 
    if (first == null) throw Error.ArgumentNull("first"); 
    if (second == null) throw Error.ArgumentNull("second"); 
    return ConcatIterator<TSource>(first, second); 
} 

隨着中說。

你可以用我的第一種方法或您的GenerateRandomContact應該返回聯繫的IEnumerable,但有問題,你有多麼想要的元素上隨機產生,或者你不指定量波紋管

public IEnumerable<Contact> GenerateRandomContact() 
{ 

    var random = new Random(Environment.TickCount); 
    for (int i = 0; i < 100; i++) 
    { 
     yield return new Contact 
     { 
      Name = $"Name_{random.Next()}" 
     }; 
    } 
} 

,或者你現在傳遞參數

但整個問題是,如果你想打電話給你的方法Enumerable.Generate,這是不可能的,你不能有靜態類,因爲擴展方法擴展方法只適用於可實例化的類型和靜態類,不能實例化。

您的電話應該是

IEnumerable<Contact> contacts = new List<Contact>(){....} 
//where contacts is an instance of type 
contacts.Generate 

即使是在你想要這個語法的情況下

contacts.Generate(GenerateRandomContact).Take(5); 

您的擴展方法應該接受功能,但在這裏,我依靠以前GenerateRandomContact(),我把100隨機接觸

public static class Extension 
{ 
    public static IEnumerable<T> Generate<T>(this IEnumerable<T> elements, Func<IEnumerable<T>> func) 
    { 
     if (func != null) 
     { 
      return func(); 
     } 

     return Enumerable.Empty<T>(); 
    } 
} 

恕我直言,儘量考慮通過你想要的金額。你的語法將會改變一點點

class Program 
    { 
     static void Main(string[] args) 
     { 
      IEnumerable<Contact> contacts = new List<Contact>() 
      { 
       new Contact 
       { 
        Name = "Name1" 
       }, 
       new Contact 
       { 
        Name = "Name2" 
       } 
      }; //load your methods from the database or create them here 

      var res = contacts.Generate(GenerateRandomContact, 5); 

      Console.ReadLine(); 
     } 

     static IEnumerable<Contact> GenerateRandomContact(int amount) 
     { 
      var random = new Random(Environment.TickCount); 

      for (int i = 0; i < amount; i++) 
      { 
       yield return new Contact 
       { 
        Name = $"Name_{random.Next()}" 
       }; 
      } 
     } 

    } 

    public class Contact 
    { 
     public string Name { get; set; } 
    } 

    public static class Extension 
    { 
     public static IEnumerable<T> Generate<T>(this IEnumerable<T> elements, Func<int, IEnumerable<T>> func, int amount) 
     { 
      if (func != null) 
      { 
       return func(amount); 
      } 

      return Enumerable.Empty<T>(); 
     } 
    } 
} 
+1

如果你想要5件以上的東西,該怎麼辦? –

+1

更改數字,他需要做的同樣的事情得到,如果沒有,然後傳遞你想要的範圍的參數 – Zinov

+1

這與'Enumerable.Range' +'Select'沒有什麼不同 –

相關問題