在含有null值的复杂类的集合(Collection)中取最大值

在日常编程中,经常遇到要在一组复杂类的集合(Collection)中做比较、取最大值或最小值。

举个最简单的例子,我们要在一个如下结构的集合中选取包含最大值的元素:

public class Class<T> where T : struct
{
    public T? Value { get; set; }
}
var ints = new List<Class<int>>()
{
    new Class<int>() { Value = 2 },
    new Class<int>() { Value = 10 },
    new Class<int>() { Value = 5 },
    new Class<int>() { Value = 10 },
};

如果不使用.Net高级特性的做法通常是:

var max = new Class<int>() { Value = Int32.MinValue };
foreach (var i in ints)
{
    if (i.Value != null && i.Value > max.Value)
    {
        max = i;
    }
}

return max;

这样的写法,除了烦琐无味以外,还有一个很明显的Bug,虽然在上面这个例子中暴露不出来,但是假设集合没有一个元素,或者组成如下:

var ints = new List<Class<int>>()
{
    new Class<int>() { Value = null },
    new Class<int>() { Value = null },
    new Class<int>() { Value = null },
};

此时此刻,我们想要返回的是包含null值的元素,而上述方法则带给我们包含Int32最小值的元素,此元素并不在ints集合中!

你会想使用Linq框架的Max(),比如:

var max = ints.Max(i => i.Value);

但事实上这个方法只能返回元素的Value成员变量,也就是int?类型,所以这也不是我们想要的。

此时此刻,正确的方法可能是:

var max = ints.First(i => i.Value == ints.Max(j => j.Value));

但,这还是有机会抛异常的,假设集合如下

var ints = new List<Class<int>>()
{
    new Class<int>() { Value = null },
    new Class<int>() { Value = null },
    new Class<int>() { Value = null },
    null
};

在这个集合里我们加了一个真正的null元素(而非包含null值的元素),ints.Max()就会抛NullReferenceException。

为了解决这个问题,我们可以将max声明改写为:

var max = ints.First(i => i.Value == ints.Max(j => { return j == null ? null : j.Value; }));

你可能已经注意到了,Max()方法中加了null值判断,但First()方法中却不需要。请先不要急于抱怨微软设计的集合方法有行为不一致的现象。

至于为什么,我将这个作业交给你,先自己在下面这个链接里挖掘一下答案吧。:)

http://referencesource.microsoft.com/

(此网站是微软早在两年前建设好的用于方便软件工程师查看.Net源代码的网站)

时间: 2024-08-03 13:20:50

在含有null值的复杂类的集合(Collection)中取最大值的相关文章

Sql与oracle中null值的区别

原贴链接请点击: 1 null值的介绍 NULL 是数据库中特有的数据类型,当一条记录的某个列为 NULL ,则表示这个列的值是未知的.是不确定的.既然是未知的,就有无数种的可能性.因此, NULL 并不是一个确定的值. 这是 NULL 的由来.也是 NULL 的基础,所有和 NULL 相关的操作的结果都可以从 NULL 的概念推导出来. 2 oracle中的null值介绍 在不知道具体有什么数据的时候,即未知,可以用NULL, 称它为空,ORACLE中,含有空值的表列长度为零.允许任何一种数据

sql server null值需要注意的地方

1.null与任何运算符运算后都为null 普通的值一般都可能进行运算符操作,但例如:ID列为int,所以可以这样:ID=ID+1等,但如果一列的值为null,null+1=null 例如 update testNullset b=b+1where b is null 查询后发现b的值没有变化,仍然为null. 2.任何值与null比较时都会返回false 普通的值可以进行"="操作,例如条件中一般都会这样出现:sUserName='张三',如果sUserName的值为null,要想找

Spark SQL中Dataframe join操作含null值的列

当在Spark SQL中对两个Dataframe使用join时,当作为连接的字段的值含有null值.由于null表示的含义是未知,既不知道有没有,在SQL中null值与任何其他值的比较(即使是null)永远不会为真.故在进行连接操作时null == null不为True,所以结果中不会出现该条记录,即左侧表格的这条记录对应右侧的值均为null.示例如下: table_a: date serverId lvSection 2018-03-04 1 10 2018-03-05 null 9 2018

微软BI 之SSIS 系列 - 对于平面文件中 NULL 值处理过程中容易极易混淆的几个细节

最近有人问我 OLE DB Destination 中的 Keep Nulls 如何控制 NULL 值的显示,为什么选中了 Keep Nulls 但是数据库中没有 NULL 值? 为什么在 Flat File Source 中勾选上了 Retain null values from the source as null values in the data flow 但是为什么目标表上显示的是一个当前日期,而不是 NULL 值等等,单开此文来解释这些非常容易混淆的概念. 在比较纯粹的 ETL 项

MySQ学习笔记之十 NULL值处理

这是MySQL一大特殊之处. 概念上,NULL意味着"没有值"或"未知值",且它被看作有点与众不同的值.为了测试NULL,你不能使用算术比较运算符例如=.<或!=.为了说明它,试试下列查询: mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL; +----------+-----------+----------+----------+ | 1 = NULL | 1 != NULL |

《奇妙的NULL值,你知道多少?》

<NULL值的多义性分析> 谈到NULL值,很多人都是很熟悉,但是深入了解后,又感觉到陌生,对其含义和用法,都无法很准确的理解.NULL在数据库和编程语言中,存在的意义和附带的含义不同. NULL这个概念,在数据库中产生的时候就存在异议.NULL值的意义现在主流的想法为:"未知值或不确定的值".至于是否应该被视为未知值或不确定的值,存在较大的争议. NULL值在编程语言中的意思为"空的引用",即变量只是申明了,但没有实例化,在内存中没有分配内存. 由于N

不再迷惑,无值和NULL值

在关系型数据库的世界中,无值和NULL值的区别是什么?一直被这个问题困扰着,甚至在写TSQL脚本时,战战兢兢,如履薄冰,害怕因为自己的一知半解,挖了坑,贻害后来人,于是,本着上下求索,不达通幽不罢休的决心(开个玩笑),遂有此文. 学习过关系型数据库的伙伴都知道,NULL是指不确定的值,在数据库中绝对是噩梦的存在:而空值,一般对字符串类型而言,指没有任何值的字符串类型,为字符类型的变量设置为空值:set @vs='',空值跟无值不同.有人可能会问,无值是什么?无值,是指数据表中没有任何数据.无值和

mysql null 值查询问题

我在开发公司内部的一个项目时遇到一个问题:select student_quality_id from STUDENT_QUALITY where mark_status=0 and batch_stauts in (2,3)结 果遇到一直找不到符合条件的student_quality_id ,后来才发现没有考虑到null值的问题,修改成 select student_quality_id from STUDENT_QUALITY where (mark_status=0 or mark_sta

Access空字符串和Null值

什么是空字符串和Null值: Microsoft Access可以区分两种类型的空值.因为在某些情况下,字段为空,可能是因为信息目前无法获得,或者字段不适用于某一特定的记录.例如,表中有一个“电话号码”字段,将其保留为空白,可能是因为不知道顾客的电话号码,或者该顾客没有电话号码.在这种情况下,使字段保留为空或输入Null值,意味着“不知道”.双引号内为空字符串则意味着“知道没有值”.采用字段的“必填字段”和“允许空字符串”属性的不同设置组合,可以控制空白字段的处理.“允许空字符串”属性只能用于“