您的位置:首页 > 编程语言 > C#

开发自己的c# linq扩展Lambda表达式函数,WhereAsync

2018-02-12 20:54 465 查看
我这几天使用EF Core开发网站的时候,突然想试着开发自己的Linq扩展表达式,因为EF Core对IQueryable泛型类型,有很多异步表达式的支持。比如,在项目中只要添加了对EF Core命名空间的using支持,那么IQueryable泛型类型就可以使用FirstAsync等函数。
于是我先查看一下IQueryable类型的Where函数结构,发现该Where函数是因为基于IEnumerable类型才可以通过System.Linq命名空间添加对Where函数的支持。
IEnumerable类型的Where函数结构为如下,通过foreach实现对自身中所有元素的遍历,并同yield关键字在循环中实现IEnumerable的泛型对象返回值://提示:该函数结构会一直变化
private static IEnumerable<TSource> WhereIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
{
int index = -1;
foreach (TSource element in source)
{
checked
{
index++;
}

if (predicate(element, index))
{
yield return element;
}
}
}而IAsyncEnumerable泛型类型中,有一个ForEachAsync可以供我们参考private static async Task ForEachAsync_<TSource>(IAsyncEnumerable<TSource> source, Action<TSource, int> action, CancellationToken cancellationToken)
{
var index = 0;
using (var e = source.GetEnumerator())
{
while (await e.MoveNext(cancellationToken)
.ConfigureAwait(false))
{
action(e.Current, checked(index++));
}
}
}可以看到IAsyncEnumerable泛型类型通过MoveNext实现对自身中所有元素的遍历。 while (await e.MoveNext(cancellationToken)
.ConfigureAwait(false))我们来实现结合以上两个函数的IAsyncEnumerable泛型类型的初步WhereAsync表达式函数public async static Task<IAsyncEnumerable<TSource>> WhereAsync<TSource>(
this IAsyncEnumerable<TSource> source,
Func<TSource, bool> predicate,
CancellationToken cancellationToken = default)
{
using (var e = source.GetEnumerator())
{
while (await e.MoveNext(cancellationToken)
.ConfigureAwait(false))
{
if (predicate(e.Current))
{
yield return e.Current;
}
}
}

}但是因为当前异步Task没有对yield关键字添加支持,所以会报错,于是我们来将这个函数进行改进一下,完整的代码如下。 public async static Task<IAsyncEnumerable<TSource>> WhereAsync<TSource>(
this IAsyncEnumerable<TSource> source,
Func<TSource, bool> predicate,
CancellationToken cancellationToken = default)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}

List<TSource> List = new List<TSource>();
using (var e = source.GetEnumerator())
{
while (await e.MoveNext(cancellationToken)
.ConfigureAwait(false))
{
if (predicate(e.Current))
{
List.Add(e.Current);
}
}
}
return List.ToAsyncEnumerable();
}我们改动一下这个函数,使其变为对IEnumerable泛型类型的WhereAsync,完整代码如下public async static Task<IEnumerable<TSource>> WhereAsync<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate,
CancellationToken cancellationToken = default)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}

List<TSource> List = new List<TSource>();
using (var e = source.ToAsyncEnumerable().GetEnumerator())
{
while (await e.MoveNext(cancellationToken)
.ConfigureAwait(false))
{
if (predicate(e.Current))
{
List.Add(e.Current);
}
}
}
return List;
}提示大家,当前c#对异步Task表达式还不能很好的支持,形成管道,所以使用中不如同步的表达式比如IEnumerable和List使用起来便捷,开发快速。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐