【问题标题】:Difficulty typing arguments for System.Linq.Enumerable.SelectSystem.Linq.Enumerable.Select 的参数输入困难
【发布时间】:2014-11-03 06:21:10
【问题描述】:

我已经盯着这个问题看了一段时间,不知道如何解决它。

我要做的就是填写与设备表中的地址匹配的 arptable 描述属性。我不想从 arptable 创建另一个集合。

错误:

无法从用法中推断方法“System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)”的类型参数。尝试明确指定类型参数。

这是有问题的代码:

 IEnumerable<ARPTABLE> GetARPTable()
    {
        IpTable arp = new IpTable();
        IEnumerable<ARPTABLE> arptable = arp.GetArpTable();


        arptable.ToList().ForEach(i =>
        {
            DeviceTable.Where(j => j.PhysicalAddress == i.MAC)
                       .Select(y =>
                           {
                               i.Description = y.Model ?? y.DeviceName;
                           });

        });

        return arptable;

    }

DeviceTable 在哪里

public ObservableCollection<Device> DeviceTable { get; set; }

感谢您的任何帮助(或更好的方法)。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    编译器出现问题,因为您的 lambda 表达式编写不正确,因此在类型推断时失败。不幸的是,该方法的整个构造都被破坏了,我不确定我是否真的理解你在这里想要完成的事情。

    但就让它编译而言,你的方法应该看起来更像这样:

    IEnumerable<ARPTABLE> GetARPTable()
    {
        IpTable arp = new IpTable();
        IEnumerable<ARPTABLE> arptable = arp.GetArpTable();
    
        foreach (var i in arptable)
        {
            Device j = DeviceTable.FirstOrDefault(j => j.PhysicalAddress == i.MAC);
    
            if (j != null)
            {
                i.Description = j.Model ?? j.DeviceName;
            }
        }
    
        return arptable;
    }
    

    一般注意:不要使用像Select() 这样的方法来简单地访问集合中的每个元素。除非您评估返回的 IEnumerable&lt;T&gt;,否则您提供给 Select() 方法的表达式实际上不会被评估,在这种情况下您没有这样做。即使您确实评估了IEnumerable&lt;T&gt;,这也是对该方法的低效误用。

    此外,虽然 List&lt;T&gt;.ForEach() 可能被某些人认为很方便,但将 IEnumerable&lt;T&gt; 转换为 List&lt;T&gt; 只是为了调用该方法是一种浪费。常规的 foreach 语句可以正常工作并且效率更高。

    【讨论】:

    • “错误:不能修改 'i' 的成员,因为它是一个 'foreach 迭代变量'”怎么办?
    • 知道了。将 ARPTABLE 从结构更改为类。谢谢。
    【解决方案2】:

    LINQ 不能用于填充数据。它是一种查询语言,因此Select 方法返回一个新序列。只需使用 foreach 即可。我想它可能看起来像这样,虽然我不确定我的逻辑是否正确。

    foreach(var table in arptable)
    {
        var device = DeviceTable.SingleOrDefault(...);
        if (device != null)
        {
            table.Description = device.Model ?? device.DeviceName;
        }
    }
    

    至于你现在的表格

    arptable.ToList().ForEach(i =>
    

    这确实没有必要,如果不需要,为什么要将序列转换为列表?只是为了使用ForEach?我们可以做得更好。

    DeviceTable.Where(j => j.PhysicalAddress == i.MAC)
               .Select(y => i.Description = y.Model ?? y.DeviceName);
    

    这将返回一个新序列,您不会将其存储在任何局部变量中。 LINQ 查询不应该有副作用,它违背了 lambda 演算,即 LINQ 本身背后的思想。

    【讨论】:

    • 值得注意的是SingleOrDefault()与原始代码有偏差,如果枚举的多个元素与谓词条件匹配,它将抛出异常。原始代码实际上更接近于LastOrDefault()。 (但我认为根据给定的代码,没有明显的理由关心订单,所以我改用FirstOrDefault(),因为它确实“提前”)。
    • @PeterDuniho 你是绝对正确的,我知道这一点,但我认为这是理想的逻辑,但我可能错了。也许他想获得更多匹配的设备并以某种方式汇总描述的最终值。
    • 我同意这很可能是理想的逻辑。哎呀,我个人会将设备表实现为字典,在执行此处的代码之前很久就强制执行每个 MAC 地址一个条目。 :) 但无论如何,从发布的代码中可以清楚地看出,突出显示可能与原始意图不同的任何内容很重要。我的评论就是为了这个目的,而不是批评你的回答。
    【解决方案3】:

    我喜欢其他答案。如果您仍想使用linq,您可以这样做:

    IEnumerable<ARPTABLE> GetARPTable()
        {
            IpTable arp = new IpTable();
            IEnumerable<ARPTABLE> arptable = arp.GetArpTable();
    
            arptable = arptable.Select(i =>
            {
                Device device = DeviceTable.SingleOrDefault(j => j.PhysicalAddress == i.MAC);
    
                if (device != null)
                {
                    i.Description = device.Model ?? device.DeviceName;
                }
    
                return i;
            });
    
            return arptable;
    
        }
    

    【讨论】:

    • 你可以写DeviceTable.SingleOrDefault(j =&gt; j.PhysicalAddress == i.MAC);而不是DeviceTable.Where(j =&gt; j.PhysicalAddress == i.MAC).SingleOrDefault();
    猜你喜欢
    • 1970-01-01
    • 2017-10-01
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多