2009-05-01 37 views
44

Tôi có một lớp (điều khiển web) có thuộc tính kiểu IEnumerable và muốn làm việc với tham số bằng LINQ.Chuyển đổi/Truyền IEnumerable thành IEnumerable <T>

Có cách nào để truyền/chuyển đổi/gọi qua phản ánh tới IEnumerable <T> không biết loại lúc biên dịch không?

Method void (IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     var type = enumerator.Current.GetType(); 
     Method2<type>(source); // this doesn't work! I know! 
    } 
} 

void Method2<T>(IEnumerable<T> source) {} 

Trả lời

56

Liệu bạn Method2 thực sự quan tâm những gì loại nó được? Nếu không, bạn chỉ có thể gọi Cast<object>():

void Method (IEnumerable source) 
{ 
    Method2(source.Cast<object>()); 
} 

Nếu bạn chắc chắn cần phải nhận được đúng loại, bạn sẽ cần phải sử dụng phản ánh.

Cái gì như:

MethodInfo method = typeof(MyType).GetMethod("Method2"); 
MethodInfo generic = method.MakeGenericMethod(type); 
generic.Invoke(this, new object[] {source}); 

Đó không phải là lý tưởng dù ... đặc biệt, nếu nguồn không phải là chính xác một IEnumerable<type> thì gọi sẽ thất bại. Ví dụ: nếu phần tử đầu tiên xảy ra là một chuỗi, nhưng nguồn là List<object>, bạn sẽ gặp sự cố.

+0

Tùy thuộc vào tình huống bạn cũng có thể sử dụng 'OfType', chỉ cần chỉ ra. Xem thêm: http://stackoverflow.com/questions/4015930/when-to-use-cast-and-oftype-in-linq –

8

Bạn có thể muốn Refactor mã của bạn để sử dụng IEnumerable.Cast<T>

Sử dụng nó như thế này:

IEnumerable mySet = GetData(); 
var query = from x in mySet.Cast<int>() 
      where x > 2 
      select x; 
+0

Yêu cầu loại tại thời gian biên dịch. Cùng một vấn đề. – andleer

+0

Điều đó là chính xác. Và cũng vậy Method2. Bạn luôn có thể truyền tới một số điện thoại có thể truy cập được:... –

2

Đây là năm sau, nhưng tôi đã giải quyết được sự cố List<Object>.

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 
    if (enumerator.MoveNext()) 
    { 
     MethodInfo method = typeof(MyClass).GetMethod("Method2"); 
     MethodInfo generic; 
     Type type = enumerator.Current.GetType(); 
     bool sameType = true; 

     while (enumerator.MoveNext()) 
     { 
      if (enumerator.Current.GetType() != type) 
      { 
       sameType = false; 
       break; 
      } 
     } 

     if (sameType) 
      generic = method.MakeGenericMethod(type); 
     else 
      generic = method.MakeGenericMethod(typeof(object)); 

     generic.Invoke(this, new object[] { source }); 
    } 
} 
3

Với .NET 4 bạn chỉ có thể bỏ source đến dynamic trước khi chuyển nó sang phương pháp. Điều này sẽ gây ra tình trạng quá tải chung đúng để được giải quyết trong thời gian chạy mà không cần bất kỳ mã phản chiếu xấu xí:

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     Method2((dynamic)source); 
    } 
} 

Như với giải pháp thứ hai của Jon, điều này chỉ sẽ làm việc nếu nguồn của bạn thực sự là một IEnumerable<T>. Nếu nó là một đồng bằng IEnumerable sau đó bạn sẽ cần phải tạo ra một phương pháp có thể chuyển đổi nó vào đúng IEnumerable<T> loại, như trong các giải pháp sau đây:

IEnumerable<T> Convert<T>(IEnumerable source, T firstItem) 
{ 
    // Note: firstItem parameter is unused and is just for resolving type of T 
    foreach(var item in source) 
    { 
     yield return (T)item; 
    } 
} 

void Method(IEnumerable source) 
{ 
    var enumerator = source.GetEnumerator(); 

    if (enumerator.MoveNext()) 
    { 
     dynamic firstItem = enumerator.Current; 
     dynamic typedEnumerable = Convert(source, firstItem); 
     Method2(typedEnumerable); 
    } 
} 
Các vấn đề liên quan