当前位置: 首页 > 编程语言 > C#

操作方法:在C#中实现短路反向三元运算符?有关系吗?Share

时间:2023-04-10 21:17:25 C#

操作方法:在C#中短路反向三元运算符?有关系吗?假设您使用三元运算符或空合并运算符或嵌套的if-else语句来选择对象的赋值。现在假设在一个条件语句中,您评估一个昂贵的或易变的操作,要求将结果放入一个临时变量中,捕获它的状态以便进行比较,然后可能进行赋值。一种语言(例如C#)将如何实现新的逻辑运算符来处理这种情况?应该?在C#中是否有处理这种情况的现有方法?其他语言?例如,当我们假设我们正在寻找直接比较时,已经克服了一些情况以减少三元或零合并运算符的冗长。请参阅使用NullCoalescing运算符的唯一方法,特别是关于如何扩展运算符的使用以支持String.IsNullOrEmpty(string)。请注意JonSkeet如何使用MiscUtil的PartialComparer将0重新格式化为null,为什么有必要这样做?好吧,看看我们如何在没有任何捷径的情况下为复杂对象编写比较方法(引用讨论中的示例):)!=0)?结果:((结果=比较(p1.Name,p2.Name))!=0)?结果:比较(p1.薪水,p2.薪水);}JonSkeet写了一个新的比较来回避相等的情况。这允许通过编写返回null的新特定方法来扩展表达式,从而允许我们使用null合并运算符:returnPartialComparer.Compare(p1.Age,p2.Age)??PartialComparer.Compare(p1.Name,p2.Name)??PartialComparer.Compare(p1.Salary,p2.Salary)??0;空合并运算符更具可读性,因为它有两个边而不是三个。布尔条件子句被分解为一个方法,在这种情况下,如果表达式必须继续,则返回null。如果我们可以更轻松地将条件放在线上,上面的表达式会是什么样子?从PartialComparer.Compare中获取返回null的表达式,并将其放入一个新的三元表达式中,该表达式允许我们使用左侧表达式的求值,以及隐式临时变量值:returnCompare(p1.Age,p2.Age)除非值==0:比较(p1.Name,p2.Name)除非值==0:比较(p1.Salary,p2.Salary);表达式的基本“流程”是:表达式A除非布尔值B,在这种情况下表达式是C我认为这更像是一个短路的倒置三元运算符,而不是一个重载的比较运算符。就我个人而言,我避免使运算符短路,只是让方法链接它:publicstaticintCompareChain(thisintprevious,Ta,Tb){if(previous!=0)returnprevious;返回Comparer.Default.Compare(a,b);}是这样使用的:inta=0,b=2;字符串x="foo",y="bar";返回a.Compare(b).CompareChain(x,y);可以由JIT内联,因此它可以像语言中内置的短路一样执行,而不会增加复杂性。通过选择是否继续由用户控制来回答您关于上述“结构”是否不仅可以应用于比较的问题。这本质上更复杂,但操作起来更灵活,所以这是不可避免的。publicstaticTElseIf(thisTprevious,FuncisOKFunccandidate){if(previous!=null&&isOK(previous))returnprevious;返回候选人();然后像这样使用连接这是为了获得最大的灵活性,因为您可以在任何阶段更改IsOk检查并且它是完全惰性的。对于OK检查在每种情况下都相同的情况,您可以像这样简化并完全避免扩展方法。publicstaticTElseIf(FuncisOKIEnumerable[]candidates){foreach(varcandidateincandidates){vart=candidate();如果(isOK(t))返回t;}thrownewArgumentException("没有一个是可以接受的");您可以使用linq执行此操作,但这会给出一个很好的错误消息并允许此publicstaticTElseIf(FuncisOKparamsFunc[]candidates){returnElseIf(isOK,(IEnumerable>)candidates);}这种风格导致可读代码如下:varbestConnection=ElseIf(IsOk,server1.GetConnection,server2.GetConnection,server3.GetConnection);如果你想允许默认值,那么:如果(isOK(t))返回t;}返回默认值(T);显然,以上所有内容都可以使用lambda表达式编写,因此您的具体示例将是:varbestConnection=ElseIfOrDefault(c=>c!=null&&!(c.IsBusy||c.IsFull),server1.GetConnection,server2.GetConnection,server3.GetConnection);你已经对这个问题有了很多好的答案,而我迟到了这个特别的聚会。但我认为值得注意的是,您的建议是我非常希望C#具有的更普遍有用的操作的特例,即在表达式上下文中命名临时计算的能力。实际上C#有这个运算符,但仅用于查询理解。我希望我们可以在C#3中将其添加为运算符:publicstaticintCompare(Personp1,Personp2)=>letages=Compare(p1.Age,p2.Age)inages!=0?ages:让names=Compare(p1.Name,p2.Name)innames!=0?名称:比较(p1.薪水,p2.薪水);“let表达式”是那些非常有用的表达式之一,我真的不明白为什么语言设计者没有在第一个版本中立即添加它。如果C#具有此功能,那么您建议:A()unlessB():C()很简单leta=A()inB()?C():a这很难理解,如果你愿意,你可以在表达式B()和C()中使用Rewards。让表达式可以用任何具有lambda的语言来模拟;当然,letx=yinz只是(x=>z)(y),但是没有用C#编写它的巧妙方法,因为C#需要转换为每个lambda上的委托类型。顺便说一下,在Roslyn中我们不使用临时变量作为let表达式,尽管我们这样做了。相反,我们甚至比它低一级,并且具有“可能产生值的一系列操作的表示,其中一个将是该表达式的值”。“letx=yinz”只是序列“allocatex,x=y,z,deallocatex”,其中第三个元素是值。在原始的roslyn之前的C#编译器中,我们有内部运算符“left”和“right”,它们是采用两个表达式并生成左侧或右侧的二元运算符,因此我们可以生成((allocatex)right((x=y)rightz))left(deallocatex)。我的观点是:我们经常收到带有不寻常标点符号的自定义语言功能请求,但实际上,通过更好地实现基本构建块,您可以自然地构建这些运算符。为了使建议的实现远离非常冗长的问题,让我们使用unless关键字运行。(表达式A)除非(布尔B)(表达式C)...仅此而已。布尔表达式B可以通过关键字value访问表达式A的值。表达式C可以在其表达式中使用unless关键字,从而允许简单的线性链接。:使用任何符号往往会降低普通开发人员的可读性。这??运算符没有被广泛使用。我自己更喜欢开发详细的代码,但我可以在一年后轻松阅读。所以你的候选人:expressionAunlessbooleanB在这种情况下expressionC.将是expressionAunlessbooleanBsothenexpressionC.虽然像我这样的很多人仍然会使用:if(B){expressionC;}else{expressionA;}当您与拥有不同背景的大型团队一起开发软件时,就会发生这种情况,其中每个人都是一种语言的团队负责人,而其他人只是用户。更多@ShuggyCoUk:啊,我看到这可能不仅仅是一个比较?我没有使用C#3和扩展方法,但我认为您可以声明,对于我之前的示例,以下是一个publicdelegateboolValidation(TtoTest);publicstaticTValidate(thisTleftside,Validationvalidator){returnvalidator(leftside)?左侧:空;其次,根据Skeet:Validationv=(Connectionc)=>(c!=null&&!(c.IsBusy||c.IsFull));连接bestConnection=server1.GetConnection().Validate(v)??server2.GetConnection().Validate(v)??server3.GetConnection().Validate(v)??无效的;这在C#中如何工作?评论表示赞赏。谢谢。回应ShuggyCoUk:那么这是C#3中的扩展方法吗?此外,这里的结果是一个int,而不是任意表达式。用于重载另一个比较方法。假设我想要一个表达式来选择最佳连接。理想情况下,我想简化以下内容:连接温度;连接bestConnection=(temp=server1.GetConnection())!=null&&!(temp.IsBusy||temp.IsFull)?temp:(temp=server2.GetConnection())!=null&&!(temp.IsBusy||temp.IsFull)?temp:(temp=server3.GetConnection())!=null&&!(temp.IsBusy||temp.IsFull)?温度:空;好的,所以可能有方法boolIsOk(Connectionc){return(c!=null&&!(c.IsBusy||c.IsFull));这将产生:连接温度;连接bestConnection=(temp=server1.GetConnection())&&IsOk(temp)?temp:(temp=server2.GetConnection())&&IsOk(temp)?temp:(temp=server3.GetConnection())&&IsOk(temp)?温度:空;但是方法链接怎么比较呢?我在想类似的东西:ConnectionbestConnection=server1.GetConnection()unless!IsOk(value)otherwiseserver2.GetConnection()unless!IsOk(value)otherwiseserver3.GetConnection()unless!IsOk(value)otherwisenull;我想到目前为止,如果我希望条件的结果是原始条件中的表达式或方法的结果,则可以跳过。我假设这些方法返回的对象要么生成成本高,要么在下次调用该方法时更改。以上是C#学习教程:Howto:Implementshort-circuitreverseternaryoperatorinC#?有关系吗?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: