c# - IEnumerable FirstOrEmpty 扩展

标签 c# generics extension-methods covariance

问题

我正在寻找一种方法来实现 FirstOrEmpty对于 IEnumerable<X>其中 X 实现 IEnumerable<T> .基本上,如果谓词不匹配任何内容,则返回 Enumerable<T>.Empty .我不想将源参数限制为 IEnumerable<IEnumerable<X>>或者因为我可能想传递一些实现 IEnumerable<X> 的东西(例如 IEnumerable<IGrouping<bool, X>> )。

使用示例

IEnumerable<T> myCollection;
var groupCheck = myCollection.GroupBy(t => t.SomeProp == 23);

var badGroup = groupCheck.FirstOrEmpty(t => !t.Key);
var goodGroup = groupCheck.FirstOrEmpty(t => t.Key);

foreach(T x in badGroup) { ... }
foreach(T x in goodGroup) { ... }

旧方法:

IEnumerable<T> myCollection = ...;
var groupCheck = myCollection.GroupBy(t => t.SomePropOnClassT == 23);

var badGroup = (groupCheck.FirstOrDefault(t => !t.Key) ?? Enumerable<T>.Empty);
var goodGroup = (groupCheck.FirstOrDefault(t => t.Key) ?? Enumerable<T>.Empty);

foreach(T x in badGroup) { ... }
foreach(T x in goodGroup) { ... }

尝试

尝试 1:

public static IEnumerable<TResult> FirstOrEmpty<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate) where TSource : IEnumerable<TResult>
{
    TSource tmp = source.FirstOrDefault(predicate);
    if(tmp != null) {
        foreach(TResult x in tmp)
        {
            yield return x; 
        } 
    }
}

尝试 2:

public static IEnumerable<TResult> FirstOrEmpty<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate) where TSource : IEnumerable<TResult>
{
    TSource tmp = source.FirstOrDefault(predicate);
    return tmp == null ? Enumerable.Empty<TResult>() : tmp;
}

最佳答案

你自己的解决方案:

public static IEnumerable<TResult> FirstOrEmpty<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
    )
    where TSource : class, IEnumerable<TResult>
{
    return source.FirstOrDefault(predicate) ?? Enumerable.Empty<TResult>();
}

确实有效。我只添加了 class约束。这意味着“TSource 必须是引用类型”,并且接口(interface)可以使用 class约束。原因是default(TSource)可能不是 null如果TSource是一些结构。你可以这样调用它:

var badGroup = groupCheck.FirstOrEmpty<IGrouping<bool, T>, T>(g => !g.Key);
var goodGroup = groupCheck.FirstOrEmpty<IGrouping<bool, T>, T>(g => g.Key);

不幸的是,编译器不够聪明,无法自己找出类型参数,因此您必须在尖括号中提供它们 <..., ...>像上面一样。我还没有找到解决方案。

现在,如果你总是将它与 IGrouping<,> 一起使用,您可能希望使用以下不太通用的方法:

public static IEnumerable<TResult> FirstOrEmpty<TKey, TResult>(
    this IEnumerable<IGrouping<TKey, TResult>> source,
    Func<IGrouping<TKey, TResult>, bool> predicate
    )
{
    return source.FirstOrDefault(predicate) ?? Enumerable.Empty<TResult>();
}

这次是这样的:

var badGroup = groupCheck.FirstOrEmpty<bool, T>(g => !g.Key);
var goodGroup = groupCheck.FirstOrEmpty<bool, T>(g => g.Key);

好消息是,使用这种方法,编译器推断您的类型参数,因此:

var badGroup = groupCheck.FirstOrEmpty(g => !g.Key);
var goodGroup = groupCheck.FirstOrEmpty(g => g.Key);

有效。

关于c# - IEnumerable FirstOrEmpty 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13751088/

相关文章:

c# - 为什么我不能在 C# 中捕获通用异常?

c# - 在 C# 中查看类型 T 的内部实现的可能性

c# - 泛型 C# 中的无界类型参数

javascript - 有谁知道关于创建基于 MVC 的组件/扩展方法的好文章?

c# - 带 Action 的 ReaderWriterLockSlim 扩展

c# - 在 .net 中使用 System.Drawing 创建验证码

c# - 如何从 ActionExecutingContext 获取路由模板

c# - WCF 服务中的错误报告?

c# - HTMLAgilityPack 和 XPath 目标

c# - 如何从对象类型定义泛型类型?