使用预初始化列表进行迭代和使用ienumerable / iqueryable进行迭代之间有什么区别?

时间:2019-10-11 17:22:37

标签: c# .net entity-framework

例如,我有一个具有以下DbSet的CustomDataContext类:

public DbSet<CustomClass> Classes { get; private set; }

以下2种情况有什么区别?

情况1:

using (var context = new CustomDataContext())
{
    var something = ....;
    var sql = $"SELECT * FROM dbo.mytable WHERE condition = {something}";
    var items = context.Classes.SqlQuery(sql).ToList(); // <--- ToList()

    foreach (var item in items)
    {
        ...
    }
}

情况2:

using (var context = new CustomDataContext())
{
    var something = ....;
    var sql = $"SELECT * FROM dbo.mytable WHERE condition = {something}";
    var items = context.Classes.SqlQuery(sql); //  <--- No ToList()

    foreach (var item in items)
    {
        ...
    }
}

就性能而言,直接迭代可枚举/可查询对象是否有任何好处?我知道案例1发生了什么,但我不知道案例2发生了什么。有人可以向我解释吗?

1 个答案:

答案 0 :(得分:1)

IEnumerable描述行为,而List是该行为的实现。使用IEnumerable时,可以使编译器有机会将工作推迟到以后,可能会一直进行优化。如果使用ToList(),则强制编译器立即对结果进行验证。

对于您列出的示例,没有明显的性能差异。

当我们利用延期执行的优势时,性能就来了。 LINQ不会生成SQL来查询数据库,直到您对它进行枚举。

考虑以下代码:

public IEnumerable<Vehicles> CaliEmissionStd()
{
    return from a in EPA.RoadVehicles
           where a.emissions.CaliEmissions == true
           select a;
}

public IEnumerable<Vehicles> Cars(IEnumerable<Vehicles> vehicles)
{
    return from a in vehicles
           where a.VehType == "Car"
           select a;
}

在这里,我们有一种方法可以选择所有符合cali排放标准的公路车辆,还有一个过滤器可以选择类型为car的子列表。

由于LINQ在枚举之前一直推迟构造查询,因此我们可以执行以下操作,以便最终得到一个SQL查询,该查询查询数据库并且仅返回相关的行。

var AutosWithCaliEmissionStd = Cars(CaliEmissionStd());

但是,如果我们从CaliEmissionStd()返回了一个列表,那么它将运行得更慢,因为该数据库将返回所有具有cali排放标准的车辆(汽车,SUV,卡车,摩托车等)的数据,而不是只是汽车,导致我们浪费时间/时间在客户端进行过滤。