C# 带null的LINQ Max()

C# 带null的LINQ Max(),c#,linq,C#,Linq,我有一个列表,其中包含一组点(带有X和Y分量) 我想得到列表中所有点的最大X,如下所示: double max = pointList.Max(p=> p.X); 问题是当列表中有一个空值而不是一个点时。解决这个问题的最佳方法是什么?好吧,你可以把它们过滤掉: pointList.Where(p => p != null).Max(p => p.X) 另一方面,如果希望将nulls视为具有X坐标0(或类似坐标)的点,可以执行以下操作: pointList.Max(p =&g

我有一个列表,其中包含一组点(带有X和Y分量)

我想得到列表中所有点的最大X,如下所示:

double max = pointList.Max(p=> p.X);

问题是当列表中有一个空值而不是一个点时。解决这个问题的最佳方法是什么?

好吧,你可以把它们过滤掉:

pointList.Where(p => p != null).Max(p => p.X)
另一方面,如果希望将
null
s视为具有X坐标
0
(或类似坐标)的点,可以执行以下操作:

pointList.Max(p => p == null ? 0 : p.X)
请注意,如果序列为空,这两种技术都将抛出。一种解决方法(如果需要)是:

pointList.DefaultIfEmpty().Max(p => p == null ? 0 : p.X)

应该有用

如果要为空点的X提供默认值:

pointList.Max(p => p == null ? 0 : p.X)
或为空列表提供默认值:

int max = points.Where(p => p != null)
                .Select(p => p.X)
                .DefaultIfEmpty()
                .Max();

尝试强制转换为null

double max = (double?)pointList.Max(p => p.X);
更多:

我不建议在这种情况下使用
DefaultIfEmpty
,因为与其他替代方法相比,它生成的SQL相当大

请看这个例子:

我们有一个页面的模块列表,希望得到“Sort”列的最大值。如果列表没有记录,则返回null
DefaultIfEmpty
检查是否为null,并在列为null时返回列数据类型的默认值

var max = db.PageModules.Where(t => t.PageId == id).Select(t => t.Sort).DefaultIfEmpty().Max();
这将生成以下SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Join1].[A1]) AS [A1]
    FROM ( SELECT 
        CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Sort] END AS [A1]
        FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
        LEFT OUTER JOIN  (SELECT 
            [Extent1].[Sort] AS [Sort], 
            cast(1 as tinyint) AS [C1]
            FROM [dbo].[PageModules] AS [Extent1]
            WHERE [Extent1].[PageId] = @p__linq__0 ) AS [Project1] ON 1 = 1
    )  AS [Join1]
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go
exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Extent1].[Sort]) AS [A1]
    FROM [dbo].[PageModules] AS [Extent1]
    WHERE [Extent1].[PageId] = @p__linq__0
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go
如果我们将该列强制转换为可为null的列,并让
Convert.ToInt32()
按如下方式处理null:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Max(t => (int?)t.Sort));
然后我们得到以下SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Join1].[A1]) AS [A1]
    FROM ( SELECT 
        CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Sort] END AS [A1]
        FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
        LEFT OUTER JOIN  (SELECT 
            [Extent1].[Sort] AS [Sort], 
            cast(1 as tinyint) AS [C1]
            FROM [dbo].[PageModules] AS [Extent1]
            WHERE [Extent1].[PageId] = @p__linq__0 ) AS [Project1] ON 1 = 1
    )  AS [Join1]
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go
exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Extent1].[Sort]) AS [A1]
    FROM [dbo].[PageModules] AS [Extent1]
    WHERE [Extent1].[PageId] = @p__linq__0
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go
我确实建议使用ExpressProfiler检查执行的SQL:

最后一个Linq表达式也可以写成:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Select(t => (int?)t.Sort).Max());
并将生成相同的SQL,但我喜欢更简洁的
.Max(t=>(int?.t.Sort)

为什么不简单:

double? maxOrNull  = pointList.
    .Where(p => p != null)
        .OrderByDescending(p => p.x)
        .FirstOrDefault();
double max = 0;
if (maxOrNull.HasValue) max = maxOrNull.Value;

这将适用于内存中的列表和Linq2Sql,而且可能也很有效。

在表达式中放置一个可为null的强制转换,以确保空白列表将强制转换为null。然后可以添加默认值

double max = pointList.Max(p=>(double?)p.X) ?? 0;

最大值为空的列如下所示

var maximum = objectEntity.where(entity => entity.property != null).max(entity => entity.property.HasValue);

上面的语句返回实体属性的最大数目

检查null对我不起作用。我使用了DefaultIfEmpty()


有趣的方法,我比我更喜欢它,因为它避免了条件,并且在结果类型上应用了
DefaultIfEmpty
。我不建议使用
DefaultIfEmpty
。请看我的答案,为什么:@Nikkelmann我相信这是一个内存中实体的LINQ查询,没有连接到任何数据库。@RamonSnir如果是这样的话,那么两者都可以:)但是现在ppl知道不要将它用于LinqToSql。或者更确切地说:LINQ to实体。他还可以使用一个可空类型,
pointList.Max(p=>p==null?(double?)null:p.X)
如果他愿意。请注意,对于可空类型
Max
,即使是空序列也不会抛出。任何为您生成SQL的ORM或工具的问题在于,它们很容易让您自食其果。您只需要处理代码,几乎没有人查看生成的SQL。这些机械翻译的问题是,它们产生“一刀切”的代码,有时,它比您可能需要的要大得多。谢谢你在这篇文章中强调这一点。总之,始终检查生成的查询+1!!+1始终检查生成的查询!您可以编写糟糕的SQL(因此我们对其进行了分析),但不知何故,当我们不分析(甚至不查看)它生成的SQL时,ORM总是受到指责!我试图使用这个方法,但是我有一个不同的查询语法,所以我似乎无法让select中的lamda表达式工作。我使用的是
Convert.ToInt32((从表2中的x开始,在x.ID上连接表2中的y等于y.ID,其中y.ProjectID==ProjectID选择x.ObservationNum).Max())有没有办法用你的语法进行连接,或者修改我的方法以获得可为空的int类型转换?@paul gibson在我的脑海中,试试“.Max(t=>(int?)t.Sort)”.Doh。就在你的答案里。谢谢:)