2008-11-10 31 views

cevap

33

bir yineleyici yazmak için en kolay yol, örneğin, bir yineleyici blok ile:

static IEnumerable<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate) 
{ 
    foreach(T value in data) 
    { 
     if(predicate(value)) yield return value; 
    } 
} 

anahtarı burada derleyici üretilmesi ile, bir yineleyici blok içine yöntemi döner "yield return", olup numaralandırıcısı (IEnumerator<T>) aynı şeyi yapar. çağrıldığında, genel tür çıkarsama otomatik T kolları, böylece sadece ihtiyaç:

int[] data = {1,2,3,4,5}; 
var odd = data.Where(i=>i%2 != 0); 

yukarıda gayet anonim türleri ile kullanılabilir. (Bu anonim değil sürece) isterseniz

Sen coure, T belirtebilirsiniz:

var odd = data.Where<int>(i=>i%2 != 0); 

Re IEnumerable (genel olmayan), iyi, en basit yaklaşım içindir ilk olarak bir IEnumerable<T> almak için .Cast<T>(...) veya .OfType<T>(...)'u kullanın. Yukarıdakiler için this IEnumerable numarasından geçebilirsiniz, ancak arayan kişi, derleyicinin bunu çıkarmasından ziyade, T belirtmelidir. Bunu, anonim bir tür olarak T ile kullanamazsınız, bu nedenle buradaki ahlaki: anonim türlerle IEnumerable'un jenerik olmayan formunu kullanmayın.

Yöntem imzasının, derleyicinin T'u tanımlayamayacağı (ve elbette bunu anonim türler için belirtemezsiniz) olduğu biraz daha karmaşık senaryolar vardır. Bu durumlarda, genellikle derleyicisinin çıkarımı ile (belki de bir pass-thru yöntemiyle) kullanabileceği farklı bir imzayı yeniden hesaba katmak mümkündür, ancak burada bir yanıt sağlamak için gerçek kodu göndermeniz gerekir. Tartışmanın ardından

(güncellenmiş)

, burada anonim türleriyle Cast<T> kaldıraç bir yolu. Anahtar, tür çıkarımında kullanılabilecek bir argüman sağlamaktır (argüman hiç kullanılmamış olsa bile). Örneğin:

static void Main() 
{ 
    IEnumerable data = new[] { new { Foo = "abc" }, new { Foo = "def" }, new { Foo = "ghi" } }; 
    var typed = data.Cast(() => new { Foo = "never used" }); 
    foreach (var item in typed) 
    { 
     Console.WriteLine(item.Foo); 
    } 
} 

// note that the template is not used, and we never need to pass one in... 
public static IEnumerable<T> Cast<T>(this IEnumerable source, Func<T> template) 
{ 
    return Enumerable.Cast<T>(source); 
} 
+0

kullanılmayan bir parametre ile bir yöntem sadece yanlış geliyor. –

+2

It * is * sadece derleyici tarafından, çalışma zamanı değil; - –

+1

Kullanılır, ve açıkça değil, daha doğrusu anlaşılır ... C# derleyicisi "çok akıllı" olsaydık açıkça belirtmek zorunda kalmak. –

2
using System; 
using System.Collections.Generic; 

namespace ExtentionTest { 
    class Program { 
     static void Main(string[] args) { 

      List<int> BigList = new List<int>() { 1,2,3,4,5,11,12,13,14,15}; 
      IEnumerable<int> Smalllist = BigList.MyMethod(); 
      foreach (int v in Smalllist) { 
       Console.WriteLine(v); 
      } 
     } 

    } 

    static class EnumExtentions { 
     public static IEnumerable<T> MyMethod<T>(this IEnumerable<T> Container) { 
      int Count = 1; 
      foreach (T Element in Container) { 
       if ((Count++ % 2) == 0) 
        yield return Element; 
      } 
     } 
    } 
} 
+0

Bu bir arabellek yineleyici; Bunun yerine, genellikle bir yineleyici bloğu kullanmak tercih edilir, yani " Listesini" ve sadece Ekle yerine "getiri döndürme Elementi" ni bırakın. –

+1

(içerik için, orijinal sürümde numaralı bir liste vardı.Eklemek, karşılığında bitirmek; Güncellenmiş sürümü tercih ederim; -) –

İlgili konular