2009-03-04 28 views
5

我正在寫一個過濾函數來返回指定的超類型的一個較大的集合(例如對象)的特定類型。這個想法是我給你一個枚舉,並且例如給我返回所有的字符串。你可以把它寫這種方式不使用泛型:強類型返回通用函數的適當方式是什麼?

public static IEnumerable Filter(IEnumerable source, Type type) 
{ 
    List<object> results = new List<object>(); 

    foreach(object o in source) 
    { 
     if(o != null && o.GetType() == type) 
     { 
      results.Add(o); 
     } 
    } 

    return results; 
} 

如果我們想有幾個不同的方式去了解它返回的仿製藥。

爲直口:

public static IEnumerable<TResult> Filter<TResult> 
          (IEnumerable source, Type type) 

傳遞一個 '例子':

IEnumerable<TResult> Filter<TResult> 
    (IEnumerable source, TResult resultType) 

最終我認爲是乾淨的:

public static IEnumerable<T> Filter<T>(IEnumerable source) 

第二類將被稱爲完全與參數(並推斷類型):

Filter(myList, "exampleString"); 

,其中作爲最終版本會有被調用與類型說明符:

Filter<string>(myList); 

什麼是強類型的通用功能,其中返回類型不會自動暗示的迴歸適當的方式在簽名? (爲什麼?)

(編輯注:我們的投入是不是類型,如IEnumerable的<牛逼>充其量這將是IEnumerable的這個函數返回的TS出其他類型的全收集的。)

回答

9

包括Linq中下面的擴展方法不正是你所需要的:

IEnumerable<T> OfType<T>(this IEnumerable enumerable); 

下面是一個使用示例:

List<object> objects = //... 

foreach(string str in objects.OfType<string>()) 
{ 
    //... 
} 

正如你所看到的,他們使用泛型參數作爲返回類型說明符。這比使用Type或字符串更簡單,更安全,並返回一個非類型安全的枚舉。

+1

所以「.NET」的方式似乎是指定類型,那是很好的瞭解,謝謝。不幸的是,我們處於2.0的世界,我們很幸運擁有泛型。 – 2009-03-04 22:00:45

+0

是的,據我所知,我們在這裏也遇到了2.0一段時間。我想就近你可以得到.Net是你最後的解決方案。唯一缺失的是擴展方法。 – Coincoin 2009-03-04 22:10:32

+0

由於引用來源和思路清晰,我將其標記爲已接受。 – 2009-03-04 22:11:49

1

最乾淨的方法是

public static IEnumerable<T> Filter<T>(IEnumerable<T> source) 

這將刪除所有非類型安全功能。然後,您可以將任何非泛型的IEnumerable成一個通用版本,鑄造呼叫

IEnumerable enumerable = GetMyEnumerable(); 
var filtered = Filter(enumerable.Cast<string>()); 

你也可以另外使它的擴展方法,使通話更加簡化。

public static IEnumerable<T> Filter<T>(this IEnumerable<T> source) 
... 
var filtered = GetMyEnumerable().Cast<string>().Filter(); 

編輯

OP提到他們只想要過濾特定類型。在這種情況下,你可以使用Enumerable。OfType

var filtered = GetMyEnumerable().OfType<SomeType>(); 
+0

您忘記了'this'這個關鍵字 - 爲您解決了這個問題。 – 2009-03-04 21:53:21

+0

@Joel謝謝!我甚至特意添加了兩次,以添加並顯示不同之處。 – JaredPar 2009-03-04 21:53:56

4

我一般喜歡最終版本 - 它指定了所有相關信息,沒有別的。鑑於具有參數的版本,如果您是新手代碼,那麼您是否認爲參數的有意義,而不僅僅是類型?

這個「虛擬參數」模式非常有用,但我通常會避開它 - 或者至少提供一個不需要它的超載。

0

這是我的2美分。我對你想要過濾的內容有點困惑。 IEnumerable是非泛型的,那麼如何過濾非泛型源並返回IEnuerable的結果。

我認爲最乾淨的是

public static IEnumerable<T> Filter<T>(IEnumerable<T> source) 

,你甚至可以把泛型類型檢查,如果你知道你的T的過濾器將是什麼樣的類型,例如只有某個接口或基類的類或對象,或者值類型等等。

public static IEnumerable<T> Filter<T>(IEnumerable<T> source) where T : class 
public static IEnumerable<T> Filter<T>(IEnumerable<T> source) where T : struct 
1

如果使用框架3.5,這IEnumerable的已經實現的:

IEnumerable<string> s = someList.OfType<string>() 
0

很顯然(對我來說,至少)說你想要的最終版本:

IEnumerable<T> Filter<T>(IEnumerable source) 

通過減少的過程,如果沒有別的。

的第一個版本:

IEnumerable<T> Filter<T>(IEnumerable source, Type type) 

必須面對瘋狂,我傳遞一個類型不約束相匹配:

第二個版本:

IEnumerable<T> Filter<T>(IEnumerable source, T type) 

讓我構建一個例子,這個例子可能很昂貴或者不適合施工。另外,如果我傳入null(無論哪種情況)呢?另外,對於單個約束,我認爲類型參數應該是T.如果它是函數的返回 - 如Func <TResult>,那麼您可以逃避TResult,但除此之外,它只是更多的輸入而不太清晰。

0

我認爲這幾乎是你想要的。

public static IEnumerable<T> OfType<T>(IEnumerable source) { 
    foreach (object obj in source) 
     if (obj is T) 
      yield return (T)obj; 
} 

稍微複雜一些的版本,但(可能)略快將

public static IEnumerable<T> OfType<T>(IEnumerable source) { 
    foreach (object obj in source) { 
     T result = obj as T; 
     if (result != null) 
      yield return result; 
    } 
} 
相關問題