2011-06-13 5 views
5

설명하기가 약간 어렵습니다. 그래서 여기에 그것은 간다. returnData (T)의 IEnumerable 목록 인 경우IEnumerable 일 때 'T'유형의 객체를 열거 할 수있는 방법

public T FooBar<T>(Func<T> function) 
{ 
    T returnData = function(); 

    // want to iterate through returnData to do something to it 

    return returnData; 
} 

, 그때 나는 반사를 사용하여 내용을 수정 returnData을 열거하고 싶습니다 :

는이 같은 기능을 가지고있다. 그러나 나는 그것을 할 수없는 것처럼 보입니다. 내가 열거 타입 returnData를 캐스팅해야 할 때, 나는 예외를 얻을 :

유형

'System.Collections.Generic.List`1 [자동차]'

의 개체를 캐스팅 할 수 없습니다 형식 :

'System.Collections.Generic.List`1 [System.Object]'.

반환 유형은 런타임에만 예를 들어 '자동차'목록이 될 것임을 알 수 없습니다. 그래서 그것이 목록이라면 반성을 사용하여 검사해야하고 그것을 통해 열거 할 수 있도록 그것을 캐스팅하려고 시도해야합니다.

잘못된 방향으로가는 경우가 아니라면. 형식이 T 인 경우 returnData을 통해 어떻게 열거 할 수 있습니까?

답변

4
if (returnData is System.Collections.IEnumerable) 
{ 
    foreach (object o in (System.Collections.IEnumerable)returnData) 
    { 
     // Do something. 
    } 
} 

정말하지만, 왜이 같은 추가 과부하하지 :

public T FooBar<T>(Func<IEnumerable<T>> function) 
+0

을 여기

은 고기와 감자입니다 과부하 아이디어는 생각하지 않았습니다. 나는 이것을 시도 할 것이다. – 7wp

6

한 가지 방법은 T에 형 제약 조건을 추가하는 것입니다, 그러나 이것은 좋지 않은 :

public T FooBar<T>(Func<T> function) where T : IEnumerable 
{ 
    // T is not strongly typed for the enumerated item 

방법을 약간 변경 한 경우 (wrt T) :

public IEnumerable<T> FooBar<T>(Func<IEnumerable<T>> function) 

그러면 열거 가능한 개체를 수락하는 보너스가 추가되어 열거 된 실제 항목에 강력한 입력을가집니다.


그래서 질문의 두 번째 읽기에서 발견, T이 변수 returnData 무엇을 의미하는지에 대한 혼란이있다. FooBar()이 전달 된 경우 List<Car>, TList<Car>이고 실제로는 List<>이라는 제네릭 형식 사양과 관련이 없습니다. 일부는 List<U>으로 생각할 수 있습니다. U은 다른 유형으로 알려지지 않은 유형입니다.

런타임에서는 U이 숨겨져있어서 T 안에 들어가는 간단한 방법이 없습니다. 다른 응답자의 추천대로 오버로드를 사용할 수 있으며 메서드를 제공하고 Func<IEnumerable<T>> 인수를받는 메서드를 제공 할 수 있습니다.

아마도 FooBar<T>이라는 목표에 대한 좀 더 자세한 내용을 통해 좀 더 구체적인 권장 사항을 만들 수 있습니다.

2

IEnumerable<T> 대신 IEnumerable으로 유형 변환을 시도 했습니까? IEnumerable을 사용하면 foreach 루프에서 계속 사용할 수 있습니다. 각 항목에 갈 것이라고 변수는 유형 object 즉 : 당신은 T는 IEnumerable를 구현 있는지 확인 먼저 확인해야

foreach(object item in (IEnumerable)T){...} 

이어야한다.

1

여기의 문제는 IEnumerable과 IEnumerable의 T가 같지 않지만 코드에서 차이점을 확인하고 계정을 확인할 수 있습니다. T의 IEnumerable은 IEnumerable을 상속하므로 비 제너릭 버전 내부의 일반 버전에 대한 검사를 감쌀 수 있습니다.

다음은 내가 작성한 작은 테스트에서 나에게 도움이되었습니다. 필요한 것을하기에 충분하다고 생각합니다.

class FooBarOfT 
{ 
    public T FooBar<T>(Func<T> function) 
    { 
     T returnData = function(); 

     //Want to iterate through returnData to do something to it. 
     if (returnData is IEnumerable) 
     { 
      // get generic type argument 
      var returnDataType = returnData.GetType(); 

      if (returnDataType.IsGenericType) 
      { 
       // this is a System.Collections.Generic.IEnumerable<T> -- get the generic type argument to loop through it 
       Type genericArgument = returnDataType.GetGenericArguments()[0]; 

       var genericEnumerator = 
        typeof(System.Collections.Generic.IEnumerable<>) 
         .MakeGenericType(genericArgument) 
         .GetMethod("GetEnumerator") 
         .Invoke(returnData, null); 

       IEnumerator enm = genericEnumerator as IEnumerator; 
       while (enm.MoveNext()) 
       { 
        var item = enm.Current; 
        Console.WriteLine(string.Format("Type : {0}", item.GetType().Name)); 
       } 

      } 
      else 
      { 
       // this is an System.Collections.IEnumerable (not generic) 
       foreach (var obj in (returnData as IEnumerable)) 
       { 
        // do something with your object 
       } 
      } 
     } 

     return returnData; 
    } 
} 

나는 또한 일부 지원 테스트 클래스 설정 :

class Foo 
{ 
    private string _fooText; 

    public Foo(string fooText) 
    { 
     _fooText = fooText; 
    } 
    public string Execute() 
    { 
     return string.Format("executed! with {0} !", _fooText); 
    } 
} 

class Bar 
{ 
    public string BarContent { get; set; } 
} 

그리고 몇 가지 테스트를 실행하는 작은 콘솔 응용 프로그램 :

class Program 
{ 
    static void Main(string[] args) 
    { 
     // tests 
     Func<string> stringFunc =() => 
      "hello!"; 

     Func<List<Foo>> listFooFunc =() => 
      new List<Foo> 
      { 
       new Foo("Hello!"), 
       new Foo("World!") 
      }; 

     Func<IEnumerable> ienumerableFooFunc =() => 
      new Hashtable 
      { 
       { "ItemOne", "Foo" }, 
       { "ItemTwo", "Bar" } 
      }; 


     var fooBarOfT = new FooBarOfT(); 

     fooBarOfT.FooBar(stringFunc); 
     fooBarOfT.FooBar(listFooFunc); 
     fooBarOfT.FooBar(ienumerableFooFunc); 

     Console.ReadKey(); 
    } 
} 
관련 문제