2012-12-02 40 views
5

Tôi có một phương pháp mở rộng sắp xếp với các chữ ký sau:Cast IEnumerable để IEnumerable <T> khi T không biết tại thời gian biên dịch

public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties) 

Chúng tôi đã viết nó trong một thời gian trở lại và nó đã được làm việc của nó. Bây giờ tôi đang tạo một điều khiển tùy chỉnh và thuộc tính DataSource là một IEnumerable (không chung chung). Có cách nào để có được loại đối tượng trong một IEnumerable không chung chung không?

Tôi chắc chắn vấn đề "sắp xếp nguồn dữ liệu điều khiển tùy chỉnh" đã được giải quyết hàng triệu lần, nhưng tôi dường như không thể tìm ra giải pháp.

Trả lời

1

Bạn có thể tạo ra một phương pháp mở rộng đó sẽ trở lại đúng loại tại thời gian chạy:

public static class LinqExtensions 
{ 
    public static Type GetElementType(this IEnumerable source) 
    { 
     var enumerableType = source.GetType(); 
     if (enumerableType.IsArray) 
     { 
      return enumerableType.GetElementType(); 
     } 
     if (enumerableType.IsGenericType) 
     { 
      return enumerableType.GetGenericArguments().First(); 
     } 
     return null; 
    } 
} 

Cập nhật: Tôi đã thêm các cơ chế mà tôi sẽ sử dụng để thực hiện các generic cụ thể IEnumerable<T> sắp xếp trên không generic IEnumerable

public static class SortingExtensions 
{ 
    public static IEnumerable<T> CustomSort<T>(this IEnumerable<T> source, string sortProperties) 
    { 
     // sort here 
    } 

    public static IEnumerable CustomSort(this IEnumerable source, string sortProperties) 
    { 
     var elementType = source.GetElementType(); 
     var genericElementType = typeof (IEnumerable<>).MakeGenericType(elementType); 

     var sortMethod = typeof (SortingExtensions).GetMethod(
      "CustomSort", 
      BindingFlags.Public | BindingFlags.Static, 
      null, 
      new [] {genericElementType, typeof (string)}, 
      null); 

     return (IEnumerable) sortMethod.Invoke(null, new object[] {source, sortProperties}); 
    } 

} 
+0

Cách tiếp cận thú vị. Tôi cũng sẽ thử. Về phương pháp sắp xếp, điều này là nhiều hơn hoặc ít hơn những gì chúng tôi đang làm, nhưng chúng tôi cũng đưa vào tài khoản sắp xếp với nhiều thuộc tính, mỗi thuộc tính có hướng riêng của nó. –

+0

Tôi đã thử giải pháp của bạn, nhưng enumerableType.GetGenericArguments(). Đầu tiên() gây ra một StackOverflowException. (Havn't có một trong số này trong lứa tuổi! :)) –

+0

Tôi tìm thấy vấn đề. Một khi phương thức này đi qua IEnumerable CustomSort tĩnh công cộng (nguồn IEnumerable này, string sortProperties) nó được gọi một lần nữa, và điều này tạo ra một vòng lặp infinate, hoặc có vẻ như vậy. –

1

Cá nhân, tôi sẽ chỉ cần sử dụng

DataSource.Cast<object>() 

và sau đó bạn có một IEnumerable<object> mà bạn có thể sử dụng chức năng CustomSort<T> của bạn. Tôi giả định ở đây rằng chức năng này có thể xử lý các đối tượng tùy ý rồi; đánh giá bởi tên thông số thứ hai, tôi đoán rằng bạn đang sử dụng Phản chiếu trong tên đó, vì vậy sẽ ổn thôi. Chỉ cần đảm bảo nó sử dụng GetType() của mỗi đối tượng khi phản ánh trên nó, không phải typeof(T), bởi vì typeof(T) rõ ràng sẽ là object và nó sẽ không nhận được danh sách các trường của đối tượng thực tế.

Tất nhiên, nếu bạn thực sự biết loại của tất cả các đối tượng trong nguồn dữ liệu tại thời gian biên dịch, bạn có thể muốn sử dụng loại mà thay vào đó, ví dụ:

DataSource.Cast<Customer>() 
+0

Bạn nói đúng về MoveNext(). Tôi đã xóa dòng đó vào thời điểm tôi tạo bài đăng này, vì vậy tôi đã viết từ bộ nhớ. Về Cast <>, tôi sẽ thử nó. Cảm ơn bạn! –

+0

@EladLachmi: OK, tôi sẽ tự do xóa phần đó khỏi câu hỏi của bạn. – Timwi

+0

Hàm CustomSort sử dụng typeof (T) để phản ánh việc tạo kiểu sắp xếp dưới dạng biểu thức lambda. Tôi thà tận dụng những gì chúng ta có, hơn là tạo ra một cái gì đó mới (cần phải trải qua QA, v.v., v.v ... Bạn biết nó như thế nào :)) –

4

Có một vấn đề cơ bản ở đây rằng một loại có thể thực hiện IEnumerable-of-T cho nhiều T cùng một lúc. Nhưng nếu chúng ta loại trừ trường hợp đó, một cách tiếp cận táo bạo là:

void Evil<T>(IEnumerable<T> data) {...} 

IEnumerable source = ... 
dynamic cheeky = source; 
Evil(cheeky); 

này về cơ bản offloads vấn đề này vào DLR, cho phép phương pháp Ác-of-T của bạn take it easy.

+1

Điều này giả định rằng 'nguồn' thực sự thực hiện' IEnumerable ' đối với một số 'T'; nhiều nguồn dữ liệu trong ngày .NET từ trước generics và do đó thực sự chỉ thực hiện 'IEnumerable', trong trường hợp đó, mã của bạn bị treo với' RuntimeBinderException'. – Timwi

+0

@Timwi câu hỏi sẽ hỏi về "truyền" nó. Nó chỉ có thể cast nó nếu nó thực sự thực hiện phiên bản chung cho một số T. Tôi không đồng ý với bạn - Tôi chỉ nói rằng sự phụ thuộc này là ngầm định trong câu hỏi. –

+0

@Timwi - Marc là đúng trong giả định của mình rằng nguồn gốc của IEnumerable không chung chung (DataSource) là một Danh sách của một số T, mà tôi không biết lúc biên dịch.Vì vậy, nó nên thực hiện IEnumerable . –

Các vấn đề liên quan