Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这个if/then语句返回true?_C#_Linq - Fatal编程技术网

C# 为什么这个if/then语句返回true?

C# 为什么这个if/then语句返回true?,c#,linq,C#,Linq,我有一个相当难看的服务工作,它运行在一个遗留数据库中,并将其与我们的生产数据库进行比较: if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null) { var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Ite

我有一个相当难看的服务工作,它运行在一个遗留数据库中,并将其与我们的生产数据库进行比较:

if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null)                        {
 var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).First();
                            // check to see if there were changes
                            if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
                            {
                                oldDbContractItem.Update(vendorContractItem);
                            }
                        }

我将在
var oldDbContratItem
上得到一个错误,“Sequence contains no elements”,但我刚刚做了一个!=空检查。这必须很简单,到底发生了什么?

使用已接受答案中的修复后,您可以使用以下步骤进一步调试LINQ情况(如果需要)。LINQ是一项令人兴奋的技术,但需要一段时间才能让人清醒过来——我认为这是一种范式转变。一针见血,因为他可能帮助建造了这些东西

LINQ的调试步骤

  • 要处理第二条语句没有结果的问题,请将
    .First()
    更改为
    .FirstOrDefault()
    如果未找到任何内容,它将返回数据类型的默认值-如果数据类型是类,它将返回空值。然后,您的第二条语句也应该使用空检查,并且没有错误

  • 然后,您可以调试LINQ语句,找出它为什么要这样做

    • 如果使用LINQ to SQL,Visual Studio 2010中的Intellisense将显示当您将鼠标悬停在查询变量(而不是查询结果)上时生成的SQL。如果您需要VS 2008的可视化工具

    • 类似地,如果使用LINQtoEntity框架,则可以使用

  • 我总是从这些工具中获取生成的SQL,将其直接粘贴到查询窗口中并在那里运行。它将向您显示返回的空集,如果这是一个问题,您可以通过可视化生成的语句的方式进一步调试它


  • 这是针对您正在执行的
    null
    的测试:

    vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null
    
    这永远是真的;将始终返回至少一个空序列。。。绝不允许
    null

    var oldDbContractItem = vendorContract.Item
      .Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
    if(oldDbContractItem != null) //would be null if there are no items
    {
      // check to see if there were changes
      if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
      {
        oldDbContractItem.Update(vendorContractItem);
      }
    }
    }
    
    您可能想测试其长度是否大于0

    不过,在我看来,有一种更简单的方法,调用
    FirstOrDefault()
    而不是
    First()
    ,并完全忽略预测试。然后,测试
    FirstOrDefault()
    的结果是否为
    null

    var oldDbContractItem = vendorContract.Item
      .Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
    if(oldDbContractItem != null) //would be null if there are no items
    {
      // check to see if there were changes
      if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
      {
        oldDbContractItem.Update(vendorContractItem);
      }
    }
    }
    

    没有元素的序列仍然是一个对象。

    因为您的查询返回了一个容器,它恰好是空的,空检查是在返回上,而不是返回所包含的内容

    试试这个

    if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).Any())
    {
      .....
    }
    

    其中
    可以返回非空值,但仍然解析为不包含元素的序列。在失败语句中,您使用的是其他内容,即
    Where().First()
    。如果
    中的序列确实为空,则该值为空。

    空序列与空序列之间存在差异(例如类似于
    新列表()
    )。您要做的是使用
    Any()
    检查序列是否包含任何元素,或者将
    First()
    替换为
    FirstOrDefault()
    ,如果序列不包含元素,则返回
    null
    。(如果使用该选项,请确保
    null
    不是可由
    First()
    返回的有效值)。

    不要运行两次查询。它效率低下,可能会在代码中引入竞争条件。另外,通过直接使用
    IEnumerator
    或使用
    foreach
    循环,可以更好地支持您的逻辑

    使用以下任一选项:

    var result = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).GetEnumerator();
    if (result.MoveNext) {
        var oldDbContractItem = result.Current;
        // ...
    }
    


    如果我能教人们关于LINQ的一件事,那就是:查询表达式的值是表示查询的对象,而不是查询结果。从根本上说,这是你的问题;您将查询视为其结果。一个问题并不是一个结果,就像一家餐厅是一个俱乐部三明治。餐厅是一种生产俱乐部三明治的设备;查询是一种产生结果的设备。

    这实际上并不能解决任何问题。问题是他对空序列的测试是错误的。您只是在掩盖错误。@Yuliy:公认的答案还建议将
    FirstOrDefault
    作为调试的一个步骤。这不是掩盖任何东西,而是使过程更易于管理……但是如果您注意到我更关注第二条代码语句而不是第一条,而不是真理测试,那么您是对的。我将把这些工具超链接留在这里,以防它们对调试LINQ情况的人有用。请注意,在您的特定情况下,@Andrew Barber有一个更优雅的解决方案(因为您想要第一个元素,如果它存在的话),我的解决方案只是测试序列中包含的内容。+1这将是一种方法,例如,您将在一个结果序列中处理(可能)多个项目,而不是仅处理一个项目。@Andrew:
    foreach
    如果您处理的是可能的多个项目,则应该这样做。第二次运行查询只是为了调用
    Any
    是愚蠢的(或者更糟糕的是,如果查询是针对共享数据存储的,它会引入竞争条件)。我更喜欢这个答案,因为从基本原理的角度来看,+1注意到原始代码不必要地运行了两次查询。