.First()是在linq级别还是在返回的可枚举集合上运行?

时间:2012-07-25 11:09:51

标签: c# .net linq

我遇到了同事代码并认为它​​可能效率低下

bool any = (from c in listDeviceMaxDate
             where c.DeviceKey == m_deviceList[i].deviceKey
             select c).Any();

if (!any)
{
    latestDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
}
else
{
    // from the list we have get the lastest max date from the flow table
    DeviceDateTimeItem temp = (from c in listDeviceMaxDate
                                where c.DeviceKey == m_deviceList[i].deviceKey
                                select c).First();

    latestDate = Convert.ToDateTime(temp.dateTimeMax);
}

我的第一直觉是存储linq查询,然后根据需要引用它,但后来我意识到First()运算符可能会阻止linq实际获取无约束查询所能执行的所有行。

我最初是如何考虑重组代码的:

var deviceList = from c in listDeviceMaxDate
                            where c.DeviceKey == m_deviceList[i].deviceKey
                            select c;

if (!deviceList.Any())
{
    latestDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
}
else
{
    // from the list we have get the lastest max date from the flow table
    DeviceDateTimeItem temp = deviceList.First();

    latestDate = Convert.ToDateTime(temp.dateTimeMax);
}

我的问题是First()对第二个linq查询的调用是否阻止它返回所有结果,因此,它是否真的更快地以原始方式执行?

1 个答案:

答案 0 :(得分:3)

它实际上取决于它是什么LINQ实现。如果它是LINQ到对象(即IEnumerable<T>),那么基本只是枚举数据它是什么,并返回第一个项目,如果一个。所以First()是道德等同于:

foreach(var val in sequence) return val;
throw OopsNoData();

Any()应与以下内容进行比较:

foreach(var val in sequence) return true;
return false;

(它可能在实际实现中使用原始迭代器,而不是foreach

然而!如果它是LINQ-to-anything-else,那么所有的赌注都会被取消。 LINQ查询(尤其是IQueryable<T>)被设计为可组合的 - 例如,我希望LINQ-to-SQL将First()转换为select TOP 1 ... TSQL查询,对于大多数其他数据库后端。所以是的,告诉它你只想要一行应该是有帮助的。然而!我也希望.Any()做一些非常相似的事情,所以不应该(理论上)是一个很大的区别。在一个完美的世界中,它甚至可能在TSQL中使用exists(...),但这个世界远非完美。

找出方法:附加一个sql跟踪器,看看最终的TSQL是什么。


这样做的最终方式更简单:

var obj = someQuery.FirstOrDefault();
if(obj == null) {
   // no match
} else {
   // do something with "obj"
}