2012-12-02 64 views
5

未知我有一個排序擴展方法具有以下簽名:投了IEnumerable到IEnumerable的<T>當T是在編譯時

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

我們寫了一段時間後,它一直在做它的事。現在我正在創建一個自定義控件,並且DataSource屬性是一個IEnumerable(非泛型)。 有沒有什麼辦法來獲取非泛型IEnumerable中的對象的類型?

我相信「排序自定義控件數據源」的問題已經解決了一百萬次,但我似乎無法找到解決方案。

回答

1

您可以創建一個擴展方法,將在運行時返回正確的類型:

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; 
    } 
} 

更新:我補充說,我會用它來執行特定仿製IEnumerable<T>排序的非機制通用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

有趣的方法。我也會試一試。關於排序方法,這或多或少是我們正在做的事情,但我們也考慮用多個屬性進行排序,每個屬性都有自己的方向。 –

+0

我試過你的解決方案,但是enumerableType.GetGenericArguments()。First()導致StackOverflowException。 (沒有這些年齡之一!:)) –

+0

我發現這個問題。一旦該方法通過公共靜態IEnumerable CustomSort(此IEnumerable源,字符串sortProperties),它會再次被調用,並且這會創建一個無限循環,或者看起來如此。 –

1

就個人而言,我只想用

DataSource.Cast<object>() 

,然後你有一個IEnumerable<object>,你可以在你的CustomSort<T>功能使用。我在這裏假設這個函數可以處理任意對象;根據第二個參數名稱判斷,我猜你正在使用Reflection,所以它應該沒問題。只是確保在反思時使用每個對象的GetType(),而不是typeof(T),因爲typeof(T)顯然是object,並且它不會得到實際對象的字段列表。

當然,如果你真的知道在編譯時的數據源中的所有對象的類型,你可能想使用該類型代替,例如:

DataSource.Cast<Customer>() 
+0

您對MoveNext()有所瞭解。當我創建這篇文章時,我已經刪除了該行,所以我從內存中寫入。關於Cast <>,我會嘗試一下。謝謝! –

+0

@EladLachmi:好的,那麼我會冒昧地從你的問題中刪除那部分。 – Timwi

+0

CustomSort 函數在反射中使用typeof(T)將該排序構造爲lambda表達式。我寧願利用我們擁有的東西,而不是創造新的東西(這將需要通過質量保證等等,等等......你知道它是如何:)) –

4

這裏有一個根本性的問題一個類型可以同時爲多個T實現IEnumerable-of-T。但是,如果我們排除這種情況下,一個厚臉皮的做法是:

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

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

這基本上卸載這個問題的DLR,讓你的邪惡的-T方法處之泰然。

+1

這假設'源'實際上實現'IEnumerable '對於某些'T'; .NET中的許多數據源來自泛型之前的日期,因此實際上只實現了'IEnumerable',在這種情況下,您的代碼崩潰時會出現'RuntimeBinderException'。 – Timwi

+0

@Timwi問題是關於「鑄造」的問題。如果它確實爲某個T實現了通用版本,那麼只能將它施放。我並不贊同你 - 我只是說這個依賴關係隱含在問題中。 –

+0

@Timwi - Marc在他假設非泛型IEnumerable(數據源)的來源是某個T的列表是正確的,這在編譯時是我不知道的。因此它應該實現IEnumerable 。 –

相關問題