【问题标题】:Convert Foreach into linq Expression将 Foreach 转换为 linq 表达式
【发布时间】:2022-01-01 04:03:00
【问题描述】:

我正在尝试从Device 表中获取针对当前客户的设备列表。我做到了,但使用了 foreach 循环,但我想使用 linq 来进行操作。

这是我的班级结构

public class Device
{
    public string type { get; set; }
    public int id { get; set; }
    public List<Role> roles { get; set; }
}


public class Role
{
    public int roleId { get; set; }
    public string roleName { get; set; }
    public int customerId { get; set; }
}

这是我的代码

var devList = list.Where(x => x.type == "device1").ToList();

foreach (var item in devList)
{
    if (item.roles != null)
    {
        var kss = item.roles.Where(z => z.customerId == kunId).FirstOrDefault();
        if (kss != null)
        {
            m.devicesList.Add(item);
        }
    }
}

我需要针对当前客户获取设备,因此我必须将我当前的用户 ID 与 customerId 进行比较。

如何将其转换为 linq-to-sql?

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    有两种方法可以解决这个问题。

    首先,您可以将所有内容放入复杂的Where 操作中:

    var devices = list.Where(d => d.type == "device1" && d.roles is object && d.roles.Any(r => r.customerId == kunId) );
    

    其次,您可以将其分散到多个单独的操作中,但每个操作都更容易理解:

    var devices = list.Where(d => d.type == "device1").
                       Where(d => d.roles is object).
                       Where(d => d.roles.Any(r => r.customerId == kunId) );
    

    任一选项的性能将相似。额外的Where() 调用会产生开销,但并没有你想象的那么多...... JITter 可以用这种代码做一些惊人的事情,看到这两个结果我不会感到惊讶完全相同的 IL。

    还要注意在这两种情况下都没有ToList() 调用。通过更长时间地使用IEnumerable,您通常可以大大提高性能和内存使用率。

    此时,我不清楚您是否只是附加到现有的 m.devicesList 或这些值是否可以替换该集合中当前可能存在的任何内容。

    假设m.devicesList 被声明为List&lt;Device&gt;(或类似),前一个选项将如下所示:

    m.devicesList.AddRange(devices);
    

    同样,没有必要曾经致电ToList()

    后者看起来像这样:

    m.devicesList = devices.ToList();
    

    我们还可以将这两个步骤合并到一个语句中。以下是四种可能的组合之一:

    m.devicesList.AddRange(list.Where(d => d.type == "device1").
                                Where(d => d.roles is object).
                                Where(d => d.roles.Any(r => r.customerId == kunId) )
                          );
    

    【讨论】:

    • 删除了我的评论和我的回答;如果检查添加项目,则错过了内部。你的好多了。
    • 非常感谢您提供这个具有正确解释的惊人解决方案。 @joel-coehoorn
    • @Joel Coehoorn 这完全不相关,但你的头像很好。
    【解决方案2】:

    所以你有一个对象kunId,它与Role.CustomerId 的类型相同。您在对象devList 中还有一个Items 序列。最后,你还有一个属性m.DevicesList,它实现了ICollection&lt;Item&gt;(=你有一个方法Add(Item)

    您当前的方法检查您的项目序列中的每个Item。如果属性Roles 为空,则忽略该项目。另一方面,如果您有一些角色,您将获得第一个或默认角色,其属性CustomerId 的值等于 kunId。如果有这样的非默认角色,那么您将项目添加到m.DevicesList

    我将重新表述这个要求。

    当且仅当 Item 具有属性 Roles 的非空值,并且这些角色中的至少一个角色具有等于 kunId 的属性 CustomerId 的值,然后您将项目添加到序列中m.DevicesList中的项目数

    var itemsToAddToMDevicesList = devList.Where(item => 
        item.Roles != null &&
        item.Roles.Where(role => role.CustomerId == kunId).Any();
    

    换句话说:您要添加到m.DeviceListItems 的序列是devList 中所有Items 的序列,其中属性Roles 具有非空值,并且至少具有属性 Roles 中的一个 Role,其属性 CustomerId 的值等于 kunId

    【讨论】:

      【解决方案3】:

      始终尝试首先用简单的自然语言“实现”您的要求。

      您需要什么设备?那些:

      1. 类型为“device1”
      2. 具有分配给给定客户的角色

      分别构建每个部分,添加必要的防护,例如roles != null 你会得到这样的结果:

      var devicesFound = list.Where(d => 
         d.type == "device1" && 
         d.roles != null && 
         d.roles.Any(r => r.customerId == kunId));
      
      m.devicesList.AddRange(devicesFound);
      

      【讨论】:

        【解决方案4】:

        您应该能够删除分配给 devList 的 linq 表达式值末尾的 .ToList()。

        此外,如果您的目标是优化您正在执行的操作,您可能会考虑维护当前代码,而不是将其转换为 linq 表达式。

        不过,如果您需要转换 foreach 循环,请查看 official microsoft documentation,您应该能够在智能感知的帮助下自动完成。

        【讨论】:

        • 请添加一些关于您提到的性能方面的解释。
        • @cly ToList() 通常会浪费 CPU 和内存。最好编写代码以坚持使用更简单的 IEnumerable,并在最后一刻保存任何 ToList() 调用。此外,用于 linq 操作的状态机有时会产生内存分配开销。如果您有良好的非 linq 代码,它有时可以胜过等效的 linq,尤其是在云 Web 或虚拟 Web 服务器等内存受限的环境中。
        • @joel-coehoorn 所以我使用的 foreach 代码比 linq 查询更好?性能也更好?仅仅因为行数我想使用 linq 而不是 foreach。
        • @JoelCoehoorn 避免ToList() 对我来说也是微不足道的。关于 LINQ 与非 LINQ 代码的陈述是我感兴趣的。开发团队承诺自 LINQ 首次发布以来,它的性能会得到如此多的改进,这就是为什么你在这里所说的关于状态机和其他内容的内容很有趣。强调“拥有好的非LINQ代码”你当然是对的。
        • @JoelCoehoorn,感谢您的解释。在内存管理需要循环的环境中,尤其是在微服务架构中,尽可能高效是关键。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多