【问题标题】:How does a IList.Distinct method throws ArgumentNullException in the given scenarioIList.Distinct 方法如何在给定场景中抛出 ArgumentNullException
【发布时间】:2017-11-21 18:50:29
【问题描述】:

我面临一个非常奇怪的问题,不确定问题出在哪里。当我浏览代码并分析所有场景时,我没有 看到无论如何它都可以通过 ArgumentNullException。

但不知何故,在生产服务器中,它会抛出以下异常:

异常详细信息:System.ArgumentNullException:值不能为空。 参数名称:source
在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 源)
在 GetDistinctValues(IList`1 textNames)

我在一个示例控制台应用程序中提取了代码。谁能告诉我当 GetDistinctValues 方法抛出这个 ArgumentNullException 时可能出现的情况?

示例代码sn-p:

private IList<string> GetDistinctValues(IList<string> textNames)
{
    var values = GetTextValues(textNames);
    var trimmedValues = values.Select(value => value.Trim());
    return trimmedValues.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();
}

public static IList<string> GetTextValues(IList<string> textNames)
{
    var values = new List<string>();
    var names = (List<string>)textNames;
    if (!names.Any())
    {
        return null;
    }

    names.ForEach(x => values.Add(GetValue(x)));

    return values;
}

private static string GetValue(string name)
{
    // returns some value depending on name

    return "someValue";
}

【问题讨论】:

  • if (!names.Any()) { return null; } in GetTextValues 看起来像候选人
  • 是的,我也认为!names.Any() 可能是罪魁祸首,因为如果names 为空,那将失败
  • 异常显示 - System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)。能不能返回trimmedValues.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();,我这里转成ToList()也能产生这个异常?
  • 也许是这样:来自:var names = (List)textNames; To : var names = textNames.Select(x => (string)x).ToList();
  • 在该行引发异常的事实并不一定 - 特别是在使用延迟设计的 Linq 时 - 意味着该行也会导致错误。 ToList 只是强制现在调用以前的方法,其中一个会引发异常。

标签: c# linq


【解决方案1】:

ToList 是一个扩展方法,可能带有这样的签名:public static List&lt;T&gt; ToList&lt;T&gt;(this IEnumerable&lt;T&gt; source)。读取异常,source 为空。因此,GetTextValues 返回 null。当没有names 时它会做什么。

【讨论】:

    【解决方案2】:

    如果你想在 LINQ 中使用你的集合,你应该 永远不会!永远! 如果您没有要返回的内容,请返回 null。相反,您应该返回 Enumerable.Empty 或空集合。如果你的函数决定它没有要返回的元素,它应该返回一个枚举器,在这种情况下,枚举器不枚举任何元素。

    考虑改变你的功能:

    public static IEnumerable<string> GetTextValues(IEnumerable<string> textNames)
    {
        if (textNames == null)
            return Enumerable.Empty<string>();
            // or consider: throw ArgumentNullException(nameof(textNames));
        return textNames.Select(textName => GetValue(textName));
    }
    

    返回枚举而不是列表的好处是,如果您的函数的用户只需要列表的前几个元素,那么只会创建几个元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      相关资源
      最近更新 更多