2016-12-19 9 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

私は通常、カスタムIEnumerable型を生成するのではなくList <>オブジェクトを作成します。だから、私はちょうど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

2つのこと:最初に、これは 'public static IEnumerable (Func ジェネレータ)'を生成しないでください。 'Action 'は入力として 'T'をとり、' Func 'は入力を持たず、' T'を出力として返します。 第2に、これは任意の量の要素を作成する簡単な方法ですが、これは誰も** To **()を呼び出す人がいない場合、またはあなたがOutOfMemoryExceptionを実行した場合にのみ有効です。 –

+0

'OutOfMemoryException'は呼び出し側の良心になります。無限のジェネレータは、関数型プログラミングスタイルのものです。 – DarkWanderer

+0

@msa不快ではなく修理していただきありがとうございます。 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()

のようなものを期待していますEnumerateするには、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クラスを作成して、特定の量に基づいて。たぶん、あなたは生成方法で金額を渡して検討すべき、または連絡先が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); 
} 

をmehotdに、連結方式などの他の拡張機能と同様に、あなたは彼らが通過する方法下記参照、IEnumerableをを渡す必要があります。

あなたは私の最初のアプローチを使用することができたり、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); 

たい場合には、あなたの拡張メソッドは、関数を受け入れる必要がありますする必要がありますが、ここで私はどこI)(前回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>(); 
    } 
} 

IMHOあなたが取るべき量。あなたの構文は少し変わります

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

数字を変更する、getの中でやる必要があるのと同じこと、必要な範囲のパラメータを渡す – Zinov

+1

これは 'Enumerable.Range' +' Select'と変わりません –

関連する問題