hello,大家好久不见,欢迎来到橙子老哥的分享时间,希望大家一起学习,一起进步。
欢迎加入.net意社区,第一时间了解我们的动态,文章第一时间分享至社区
社区官方地址:https://ccnetcore.com (上千.neter聚集地)(当前注册人数:2400)
官方微信公众号:公众号搜索 意.Net
官方微信小程序:小程序搜索 意.Net
添加橙子老哥微信加入官方微信群:chengzilaoge520
团队官网/产品矩阵:https://SharpDance.cn
1、概述
废话少说,今天来给大家讲讲一个冷知识,非常非常冷,冷到都几乎以为是微软写的bug,当然,微软这么严谨的c#,这么做,肯定有他的理由
Sum,就是一个经常用于求和的linq方法,使用频率也是非常高,特别是要求对金额等一些数字进行计算用的多
先给大家卖个关子,提出几个关于Sum的问题,请问:
[0,null,0],Sum求和是多少
[null,null,null],Sum求和是多少
var result = new List<decimal?>() { 0, null, 0 }.Sum();
var result2 = new List<decimal?>() { null, null, null }.Sum();同时,我们再看看具体Sum是返回什么的:
public static decimal? Sum([NotNull, InstantHandle] this IEnumerable<decimal?> source)
,位置:class System.Linq.Enumerable)返回 decimal? 哦,可空类型
大家可以凭借着自己的经验去思考下
2、解答
其实很多小伙伴已经猜到了,无论传入是0还是null,返回的都是0
这样其实很简单,我们看一下他的源码实现:
public static Decimal? Sum(this IEnumerable<Decimal?> source) => source.Sum<Decimal, Decimal>();
privatestatic TSource? Sum<TSource, TAccumulator>(this IEnumerable<TSource?> source)
where TSource : struct, INumber<TSource>
where TAccumulator : struct, INumber<TAccumulator>
{
if (source == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
TAccumulator zero = TAccumulator.Zero;
foreach (TSource? nullable in source)
{
if (nullable.HasValue)
checked { zero += TAccumulator.CreateChecked<TSource>(nullable.GetValueOrDefault()); }
}
returnnew TSource?(TSource.CreateTruncating<TAccumulator>(zero));
}这段源码是.net8的,如果大家翻过.net6的源码,就很简单了,微软没有对类型进行封装,而是每个struct都复制一堆重复的代码,这段被封装后的方法,我们分析下流程:
初始化数据:
TAccumulator zero = TAccumulator.Zero;循环累加:
zero += TAccumulator.CreateChecked<TSource>new一个Decimal,赋值
TSource.CreateTruncating<TAccumulator>(zero)其实TSource.CreateTruncating中,是为了判断是否类型相等,如果类型是一样的,直接返回
换句话来说,他在初始化数据的时候,就定了数据类型,TAccumulator.Zero这个是一个抽象的,我们看一下Decimal的实现
static Decimal INumberBase<Decimal>.Zero => Decimal.Zero;嗯,没错,sum的第一件事,其实就是创建了默认值0,所以他,永远也不会返回null
所以问题就来了,作为一门如此严谨的编程语言,为什么微软要把一个永远不会返回null的方法,返回一个可空类型呢?而且这样的设计还不少,不单单是Decimal,微软这么做肯定是有原因的
大家可以再思考一下
3、解答
原因之一:与Sql语义兼容 总所皆知,linq既可以使用在内存中,也可以使用在EF中,翻译成sql
数据源类型 | 场景 | 返回值类型 | 返回值可能为null吗? |
|---|---|---|---|
List in memory | 空集合/全是 null | Decimal? | 永远返回 0 |
EF Core 查询 | SQL 中全是 NULL | Decimal? | 可能返回 null |
很明显,微软想到了这一点,为了兼容Sql的这种数据类型,统一Api,真可谓是用心良苦
4、深思
比起怎么解决这个问题,其实我们更应该反思,这个问题为什么会出现,我们应该注意什么
我给大家一个实际场景
比如你要统计一列数据的合,但是这些数据可能是空行,压根就没有,如果你直接使用sum进行求和,返回了个0,结果实际返回与预期想返回null不符合,相当于被sum吃了null的状态
5、End
最后,献上我们团队的官网:https://SharpDance.cn构建智能未来的开发者社区 专注于.NET技术、人工智能与互联网前沿技术的专业开发者社区。 我们致力于推动技术创新,连接优秀开发者,共同探索智能时代的无限可能。
798

被折叠的 条评论
为什么被折叠?



