2008-11-10 9 views

답변

33

임의 반복기를 작성하는 가장 쉬운 방법은, 예를 들어, 반복자 블록이다

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

키 여기 컴파일러가 생성하여, 반복기 블록에있어서 변은 "yield return"인 열거 자 (IEnumerator<T>)는 동일한 기능을 수행합니다. 라고 할 때, 일반적인 형식 유추가 자동으로 T을 처리하는, 그래서 당신은 단지 필요

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

위의 잘 익명 형식을 사용할 수 있습니다. (이 익명없는만큼) 당신이 원하는 경우

당신은 coure의, T을 지정할 수 있습니다

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

다시 IEnumerable (제네릭이 아닌)이, 음, 가장 간단한 방법은입니다 호출자는 .Cast<T>(...) 또는 .OfType<T>(...)을 사용하여 IEnumerable<T>을 먼저받습니다. 위의 경우 this IEnumerable을 전달할 수 있지만 호출자는 컴파일러에서 유추하지 않고 T을 지정해야합니다. 익명 형식 인 T과 함께 사용할 수 없으므로 익명 형식 인 IEnumerable의 일반 형식을 사용하지 마십시오.

메서드 서명이 컴파일러에서 T을 식별 할 수없는 약간 더 복잡한 시나리오가 있습니다 (물론 익명 형식에도 지정할 수 없습니다). 그러한 경우 일반적으로 컴파일러 이 추론을 통해 (아마도 패스 스루 메서드를 통해) 사용할 수있는 다른 서명으로 다시 팩할 수 있지만 여기에 답변을 제공하려면 실제 코드를 게시해야합니다. 토론에 이어

(업데이트)

, 여기에 익명 형식으로 Cast<T>을 활용하는 방법입니다. 열쇠는 형식 유추에 사용할 수있는 인수를 제공하는 것입니다 (인수가 사용되지 않더라도). 예를 들어 :

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

사용되지 않는 매개 변수를 사용하는 방법은 잘못된 것 같다. –

+2

It * is * used .... 그냥 컴파일러가 아닌 런타임에 - –

+1

그것은 사용되었지만 제공되었지만 명시 적으로 오히려 추측 된 것이 아닙니다 ... C# 컴파일러가 "너무 똑똑"하지 않으면 명시 적으로 지정해야한다. –

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

이것은 버퍼 된 반복자입니다. 일반적으로'List '을 삭제하고 추가 대신에 "yield return element"를 사용하는 반복자 블록을 사용하는 것이 바람직합니다. –

+1

(문맥을 위해, 본래 버전에는 목록 가 있었다.대가로 추가, 마무리; 나는 업데이트 된 버전을 선호한다 .-p) –

관련 문제