使用LINQ查找列表中的项目,但得到的“值不能为空,参数名称:来源”

wnrlj8wa  于 2023-05-26  发布在  其他
关注(0)|答案(7)|浏览(197)

当使用LINQ从列表中获取数据时,我遇到了这个错误。如何解决这个问题?
值不能为空。参数名称:来源

var nCounts = from sale in sal
              select new
              {
                  SaleID = sale.OrderID,
                  LineItem = from sli in sale.LineItems
                             group sli by sli.Item into ItemGroup
                             select new
                             {
                                 Item = ItemGroup.Key,
                                 Weeks = ItemGroup.Select(s => s.Week)
                             }
              };

foreach (var item in nCounts)
{
    foreach (var itmss in item.LineItem)
    {
        // MessageBox.Show(itmss.Item.Name);
        itemsal.Add(new Roundsman.BAL.WeeklyStockList(itmss.Item.Name.ToString(),
                    itmss.Item.Code.ToString(),
                    itmss.Item.Description.ToString(),
                    Convert.ToInt32(itmss.Item.Quantity), 2, 2, 2, 2, 2, 2, 2, 2, 2));
    }                      
}

执行我的LINQ后得到的错误,我得到了这种类型的结果(一行,原始):
System.Linq.Enumerable.WhereSelectListIterator<Roundsman.BAL.销售,<> f__AnonymousType1 <int,System.Collections.Generic.IEnumerable <<> f__AnonymousType0 <Roundsman.BAL.Items.Item,System.Collections.Generic.IEnumerable<Roundsman.BAL.WeeklyRecord>>>>>

zd287kbt

zd287kbt1#

您收到的错误来自另一个方法,而不是这里显示的方法。它是一个接受名为“source”的参数的方法。在Visual Studio选项对话框中,禁用“仅我的代码”,禁用“单步执行属性和运算符”并启用“启用.NET Framework源单步执行”。确保可以找到.NET符号。然后调试器将中断内部.NET方法,如果它不是你自己的。然后检查堆栈跟踪,找出传递的值是null,但不应该是null。
您应该寻找的是一个变成null的值,并防止这种情况发生。从代码中可以看出,可能是itemsal.Add行中断了。

编辑

由于你似乎在调试方面遇到了麻烦,特别是LINQ,让我们尝试一步一步地帮助你(如果你仍然想尝试经典的方法,请注意上面扩展的第一部分,我第一次没有完成):

  • 通过分割代码来缩小可能的错误场景;
  • 用故意不是null的东西替换可能最终为null的位置;
  • 如果都失败了,把LINQ语句重写为循环,然后一步一步地执行。

第一步

首先,通过将代码拆分为可管理的片段,使代码更具可读性:

// in your using-section, add this:
using Roundsman.BAL;

// keep this in your normal location
var nCounts = from sale in sal
              select new
              {
                  SaleID = sale.OrderID,
                  LineItem = GetLineItem(sale.LineItems)
              };

foreach (var item in nCounts)
{
    foreach (var itmss in item.LineItem)
    {
        itemsal.Add(CreateWeeklyStockList(itmss));
    }
}

// add this as method somewhere
WeeklyStockList CreateWeeklyStockList(LineItem lineItem)
{
    string name = itmss.Item.Name.ToString();  // isn't Name already a string?
    string code = itmss.Item.Code.ToString();  // isn't Code already a string?
    string description = itmss.Item.Description.ToString();  // isn't Description already a string?
    int quantity = Convert.ToInt32(itmss.Item.Quantity); // wouldn't (int) or "as int" be enough?

    return new WeeklyStockList(
                 name, 
                 code, 
                 description,
                 quantity, 
                 2, 2, 2, 2, 2, 2, 2, 2, 2
              );
}

// also add this as a method
LineItem GetLineItem(IEnumerable<LineItem> lineItems)
{
    // add a null-check
    if(lineItems == null)
        throw new ArgumentNullException("lineItems", "Argument cannot be null!");

    // your original code
    from sli in lineItems
    group sli by sli.Item into ItemGroup
    select new
    {
        Item = ItemGroup.Key,
        Weeks = ItemGroup.Select(s => s.Week)
    }
}

当然,上面的代码是从我的头上,因为我不知道你有什么类型的类,因此不能在发布之前测试代码。然而,如果你编辑它直到它是正确的(如果它不是那么开箱即用),那么你已经站在一个很大的机会,实际的错误变得更加清晰。如果没有,您至少应该看到一个不同的堆栈跟踪(我们仍然热切地等待!).

第二步

下一步是仔细替换可能导致空引用异常的每个部分。我的意思是你替换这个:

select new
{
    SaleID = sale.OrderID,
    LineItem = GetLineItem(sale.LineItems)
};

就像这样

select new
{
    SaleID = 123,
    LineItem = GetLineItem(new LineItem(/*ctor params for empty lineitem here*/))
};

这将产生垃圾输出,但会将问题进一步缩小到潜在的违规行。对LINQ语句中可能以null结尾的其他地方(几乎所有地方)执行上述操作。

第三步

这一步你得自己做。但是,如果LINQ失败了,并给您带来了这样的麻烦和这样的不可读或难以调试的代码,那么请考虑一下您遇到的下一个问题会发生什么?如果它在现场环境中失败了,你必须在时间压力下解决它=
寓意:学习新的技术总是好的,但有时候,抓住一些清晰易懂的东西会更好。我并不反对LINQ,我喜欢它,但在这个特殊的情况下,让它休息一下,用一个简单的循环修复它,然后在半年左右的时间里重新访问它。

总结

事实上,没什么可总结的。我走得更远一点,然后我通常会去与长期延长的答案。我只是希望它能帮助您更好地解决问题,并为您提供一些工具,让您了解如何缩小难以调试的情况,即使没有高级调试技术(我们还没有讨论)。

xfyts7mz

xfyts7mz2#

此异常可能指向名为source的LINQ参数:

System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector)

由于LINQ查询(var nCounts = from sale in sal)中的source参数是' sal ',我假设名为'sal'的列表可能为null。

qoefvg9y

qoefvg9y3#

我认为,如果数据库模型不正确,并且底层数据包含模型试图Map到非空对象的空值,则可能会出现此错误。
例如,一些自动生成的模型可以尝试将nvarchar(1)列Map到char而不是string,因此如果该列包含null,则当您尝试访问数据时会抛出错误。
请注意,如果您希望LinqPad生成这样的模型,它有一个兼容性选项,但默认情况下可能不会这样做,这可能解释了它不会给予您错误。

js4nwp54

js4nwp544#

此错误可能发生在多个地方,最常见的是在空集合上运行进一步的LINQ查询。LINQ作为查询语法可能看起来比实际更安全。考虑以下示例:

var filteredCollection = from item in getMyCollection()
                         orderby item.ReportDate
                         select item;

这段代码不是NULL SAFE,这意味着如果getMyCollection()返回null,您将得到Value cannot be null. Parameter name: source错误。很烦!但这是完全有意义的,因为LINQ Query语法只是这个等效代码的语法糖:

var filteredCollection = getMyCollection().OrderBy(x => x.ReportDate);

如果开始的方法返回null,这显然会崩溃。
为了防止这种情况,您可以在LINQ查询中使用null合并运算符,如下所示:

var filteredCollection = from item in getMyCollection() ?? 
                              Enumerable.Empty<CollectionItemClass>()
                         orderby item.ReportDate
                         select item;

但是,您必须记住在任何相关查询中执行此操作。最好的方法(如果您控制生成集合的代码)是使其成为一种编码实践,永远不要返回空集合。在某些情况下,从“getCustomerById(string id)”这样的方法返回一个null对象是可以的,这取决于你的团队编码风格,但是如果你有一个返回业务对象集合的方法,比如“getAllcustomers()”,那么它永远不应该返回一个null数组/enumerable/等。总是总是使用if检查,null合并操作符,或其他一些开关来返回空数组/列表/可枚举等,以便方法的消费者可以自由地LINQ结果。

pgx2nnw8

pgx2nnw85#

下面是更多将产生参数null异常的代码示例:

List<Myobj> myList = null;
//from this point on, any linq statement you perform on myList will throw an argument null exception
myList.ToList();
myList.GroupBy(m => m.Id);
myList.Count();
myList.Where(m => m.Id == 0);
myList.Select(m => m.Id == 0);
//etc...
5q4ezhmt

5q4ezhmt6#

好吧-我的情况并不严格相关的这个问题,但我结束了在这个页面上时,谷歌搜索相同的例外;当我得到这个异常时,我用LINQ查询了一个SQL数据库。

private Table<SubscriptionModel> m_subscriptionsSql;
var query = from SubscriptionModel subscription in m_subscriptionsSql ...

结果我忘记了初始化我在LINQ查询中使用的Table示例变量。

m_subscriptionsSql = GetTable<SubscriptionModel>();
pw136qt2

pw136qt27#

我昨晚也遇到了同样的错误,对我来说,原因是DbSet上没有setter,所以EF无法对集合做任何事情,因此source is null
解决办法就是改变
public DbSet<MyObject> MyObjects { get; }

public DbSet<MyObject> MyObjects { get; set; }

相关问题