强类型返回泛型函数的适当方法是什么?

时间:2009-03-04 21:45:34

标签: c# generics

我正在编写一个过滤器函数来返回从更大的超类型集合(例如对象)中指定的特定类型。这个想法是我给你一个可枚举的,你举例说明了所有的字符串。你可以这样写,没有泛型:

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&lt; T&gt;。最好是IEnumerable。这个函数将Ts退出其他类型的整个集合。)

7 个答案:

答案 0 :(得分:9)

Linq中包含的以下扩展方法正是您所需要的:

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

以下是一个用法示例:

List<object> objects = //...

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

如您所见,他们使用泛型参数作为返回类型说明符。这比使用Type或字符串更简单,更安全,并返回非类型安全枚举。

答案 1 :(得分:4)

我通常更喜欢最终版本 - 它指定所有相关信息而不是其他。给定带参数的版本,如果您不熟悉代码,那么您不希望参数的有意义,而不仅仅是类型吗?

偶尔这种“伪参数”模式很有用,但我通常会避开它 - 或者至少提供一个不需要它的过载。

答案 2 :(得分: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>();

答案 3 :(得分:1)

如果您使用的是框架3.5,则已在IEnumerable中实现:

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

答案 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

答案 5 :(得分: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.如果它是函数的返回,你可以使用TResult - 比如Func&lt; TResult&gt ;,但是否则它只是更少的清晰度打字。

答案 6 :(得分: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;
    }
}