开发自己的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使用起来便捷,开发快速。
于是我先查看一下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使用起来便捷,开发快速。
相关文章推荐
- [分享]发布自己C#开发的ReSharper2.0 for VS2003/2005 注册机
- C# WinForm开发系列之c# 通过.net自带的chart控件绘制饼图,柱形图和折线图的基础使用和扩展
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第三节 VSTS模版的体系概述
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第五节 分析过程模版的定义文件
- C#自制Web 服务器开发:用C#开发自己的Web服务器
- 使用C#开发自己的web服务器(图)
- C#基础系列:开发自己的窗体设计器(总纲)
- [C#]一步一步开发自己的自动代码生成工具之五:DAL层模板
- C# WinForm开发系列之c# 通过.net自带的chart控件绘制饼图,柱形图和折线图的基础使用和扩展
- 发布自己C#开发的ReSharper2.0 for VS2003/2005 注册机
- 今天没事,看到一个用C#开发OutLook插件的例子,顺便自己做了一个
- 自己整理的C#开发工具
- 从零开始编写自己的C#框架(2)——开发前准备工作
- C#软件开发实例.私人订制自己的屏幕截图工具(八)添加键盘操作截图的功能
- C#软件开发实例.私人订制自己的屏幕截图工具(九)使用自定义光标,QQ截图时的光标
- c# 扩展LINQ的order by函数支持传递列名作为字符串
- [c#]一步一步开发自己的自动代码生成工具之一:获取sql2005的数据库表结构
- C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)
- SuperMap iDesktop扩展开发,如何快速的定制自己的系统
- C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能