草庐IT

c# - 处理导致空序列等的 LINQ 语句的最佳实践?

coder 2023-07-11 原文

...我有点困惑,或者不确定如何处理 LINQ 语句引起的错误。我只是喜欢能够根据某些标准...使用 单行 代码从集合中提取一个或多个项目。太棒了。

但让我感到困惑的是错误处理或边界条件检查。如果我想使用 First() 检索项目,并且没有项目 满足我的查询,则会引发异常。这有点令人失望,因为现在我必须用单独的 try/catch block 包装每个 LINQ 语句。对我来说,代码开始看起来有点困惑,特别是因为我最终不得不在 try/catch block 之外声明变量,所以我可以稍后使用它们的 (null) 值(在捕获 block )。

这里有人了解我的困境吗?如果我必须将每个 LINQ 语句包装在 try/catch block 中,我会这样做,因为它仍然比编写各种 for 循环来完成同样的事情要好得多。但是一定有更好的方法,对吧? :) 我想听听这里的其他人在这种情况下会怎么做。

**更新**

谢谢你们的回答,伙计们,他们很有帮助。我还想提出的另一件事是,沿着 LINQ 的“单一性”,如果我想获得一些 .some_value.some_value.some_other_value,如果我采用一种必须检查 Nullable 的方法,我必须首先从最基本的 LINQ 查询开始,然后我可以查询我正在寻找的结果属性。我想这没有办法解决吗?

最佳答案

当您知道集合中有一个或多个项目时使用 First。当您知道集合中只有一项时,请使用 Single。如果您不知道这些事情,那么不要使用这些方法。使用执行其他操作的方法,例如 FirstOrDefault()、SingleOrDefault() 等。

例如,你可以说:

int? first = sequence.Any() ? (int?) sequence.First() : (int?) null;

这比

要少得多
int? first = null;
try { first = sequence.First(); } catch { }

但仍然不是很好,因为它重复了序列的第一项。在这种情况下,我会说如果没有序列运算符可以执行您想要的操作,那么编写您自己的

继续我们的示例,假设您有一个整数序列并且想要获取第一项,或者,如果没有,则返回 null。没有内置的序列运算符可以执行此操作,但很容易编写:

public static int? FirstOrNull(this IEnumerable<int> sequence)
{
    foreach(int item in sequence)
        return item;
    return null;
}

甚至更好:

public static T? FirstOrNull<T>(this IEnumerable<T> sequence) where T : struct
{
    foreach(T item in sequence)
        return item;
    return null;
}

或者这个:

struct Maybe<T>
{
    public T Item { get; private set; }
    public bool Valid { get; private set; }
    public Maybe(T item) : this() 
    { this.Item = item; this.Valid = true; }
}

public static Maybe<T> MyFirst<T>(this IEnumerable<T> sequence) 
{
    foreach(T item in sequence)
        return new Maybe(item);
    return default(Maybe<T>);
}
...
var first = sequence.MyFirst();
if (first.Valid) Console.WriteLine(first.Item);

但是无论您做什么,都不要处理您提到的那些异常。这些异常不是要处理的,它们是为了告诉您您的代码中有错误。你不应该处理它们,你应该修复错误。在它们周围放置 try-catch 是隐藏错误,而不是修复错误

更新:

Dave 询问如何制作带有谓词的 FirstOrNull。很容易。你可以这样做:

public static T? FirstOrNull<T>(this IEnumerable<T> sequence, Func<T, bool> predicate) where T : struct
{
    foreach(T item in sequence)
        if (predicate(item)) return item;
    return null;
}

或者像这样

public static T? FirstOrNull<T>(this IEnumerable<T> sequence, Func<T, bool> predicate) where T : struct
{
    foreach(T item in sequence.Where(predicate))
        return item;
    return null;
}

或者,甚至不打扰:

var first = sequence.Where(x=>whatever).FirstOrNull();

谓词没有理由必须继续 FirstOrNull。为了方便起见,我们提供了一个采用谓词的 First(),这样您就不必键入额外的“Where”。

更新:Dave 问了另一个后续问题,我认为这可能是“如果我想说 sequence.FirstOrNull().Frob().Blah().Whatever() 会怎样,但是沿线的任何一个都可以返回空值?”

我们考虑过向 C# 添加一个 null 传播成员访问运算符,暂定为 ?。 -- 也就是说,您可以说

x = a?.b?.c?.d;

如果 a、b 或 c 产生 null,那么结果就是将 null 分配给 x。

显然我们实际上并没有为 C# 4.0 实现它。它可能是该语言假设的 future 版本的工作项目...更新“猫王运算符”已添加到 C# 6.0,耶!

请注意,C# 确实有空合并运算符:

(sequence.FirstOrNull() ?? GetDefault()).Frob().Blah().Whatever()

表示“如果 FirstOrNull 返回非空值,则将其用作 Frob 的接收者,否则调用 GetDefault 并将其用作接收者”。另一种方法是再次编写您自己的:

public static T FirstOrLazy<T>(this IEnumerable<T> sequence, Func<T> lazy) 
{
    foreach(T item in sequence)
        return item;
    return lazy();
}

sequence.FirstOrLazy(()=>GetDefault()).Frob().Blah().Whatever();

现在,如果有第一项,您将获得第一项;如果没有,则获取调用 GetDefault() 的结果。

关于c# - 处理导致空序列等的 LINQ 语句的最佳实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3688436/

有关c# - 处理导致空序列等的 LINQ 语句的最佳实践?的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  6. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  7. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  8. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

随机推荐