操作方法:短路倒置三元运算符,例如C#?有关系吗? [英] How-to: short-circuiting inverted ternary operator implemented in, e.g. C#? Does it matter?

查看:77
本文介绍了操作方法:短路倒置三元运算符,例如C#?有关系吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您正在使用三元运算符,空合并运算符或嵌套的if-else语句来选择对一个对象的赋值.现在假设在条件语句中,您需要对昂贵或易失的操作进行评估,要求将结果放入一个临时变量中,捕获其状态,以便可以对其进行比较,然后进行潜在赋值.

Suppose you are using the ternary operator, or the null coalescing operator, or nested if-else statements to choose assignment to an object. Now suppose that within the conditional statement, you have the evaluation of an expensive or volatile operation, requiring that you put the result into a temporary variable, capturing its state, so that it can be compared, and then potentially assigned.

考虑使用的语言(例如C#)如何实现新的逻辑运算符来处理这种情况?应该是?在C#中是否存在处理这种情况的现有方法?其他语言?

How would a language, such as C#, for consideration, implement a new logic operator to handle this case? Should it? Are there existing ways to handle this case in C#? Other languages?

例如,当我们假设我们正在寻找直接比较时,已经克服了降低三元或空合并运算符的冗长性的某些情况.请参阅使用Null合并运算符的独特方法,尤其是有关如何扩展操作员以支持String.IsNullOrEmpty(string)的讨论.请注意 Jon Skeet 如何使用来自PartialComparer. arachsys.com/csharp/miscutil/"rel =" nofollow noreferrer> MiscUtil ,将0 s重新格式化为null s

Some cases of reducing the verbosity of a ternary or null coalescing operator have been overcome, when we assume that we are looking for direct comparisons, for example. See Unique ways to use the Null Coalescing operator, in particular the discussion around how one can extend the usage of the operator to support String.IsNullOrEmpty(string). Note how Jon Skeet is using the PartialComparer from MiscUtil, to reformat 0s to nulls,

为什么这可能是必需的?好吧,看看我们如何为没有任何捷径的复杂对象编写比较方法(引用的讨论中的示例):

Why is this possibly necessary? Well, take a look at how we write a comparison method for complex objects without any shortcuts (examples from the cited discussions):

public static int Compare( Person p1, Person p2 )
{
    return ( (result = Compare( p1.Age, p2.Age )) != 0 ) ? result
        : ( (result = Compare( p1.Name, p2.Name )) != 0 ) ? result
        : Compare( p1.Salary, p2.Salary );
}

Jon Skeet编写了一个新的比较,以回退相等的情况.这允许通过编写新的返回null的特定方法来扩展表达式,从而使我们可以使用null合并运算符:

Jon Skeet writes a new comparison to fallback the equality case. This allows the expression to extend by writing a new specific method which returns null, allowing us to use the null coalescing operator:

return PartialComparer.Compare(p1.Age, p2.Age)
    ?? PartialComparer.Compare(p1.Name, p2.Name)
    ?? PartialComparer.Compare(p1.Salary, p2.Salary)
    ?? 0;

空合并运算符更具可读性,因为它有两个方面,而不是三个方面.布尔条件子句分为一个方法,在这种情况下,如果必须继续表达式,则返回null.

The null coalescing operator is more readable because it has two sides, not three. The boolean condition clause is separated into a method, in this case returning null if the expression must be continued.

如果我们可以更轻松地将条件置于行内,则上面的表达式会是什么样?从PartialComparer.Compare中返回null的表达式中,并将其放置在新的三元表达式中,该表达式允许我们使用带有隐式临时变量value的左侧表达式的求值:

What would the above expression look like if we could more easily put the condition in-line? Take the expression from PartialComparer.Compare which returns null, and place it in a new ternary expression which allows us to use the evaluation of the left-side expression, with an implicit temporary variable value:

return Compare( p1.Age, p2.Age ) unless value == 0
     : Compare( p1.Name, p2.Name ) unless value == 0
     : Compare( p1.Salary, p2.Salary );

表达式的基本流"为:

表达式 A ,除非 boolean B ,在这种情况下 expression C

expression A unless boolean B in which case expression C

我想这不是一个重载的比较运算符,而是一个短路的倒置三元运算符.

Rather than being an overloaded comparison operator, I suppose this is more like a short-circuiting inverted ternary operator.

  • 这种逻辑有用吗?当前,空合并为我们提供了一种使用条件表达式(value == null)进行此操作的方法.
  • 您还想对哪些其他表达式进行测试?我们听说过(String.IsNullOrEmpty(value)).
  • 就运营商,关键字而言,用语言来表达这一点的最佳方式是什么?
  • Would this type of logic be useful? Currently the null coalescing provides us a way to do this with the conditional expression (value == null).
  • What other expressions would you want to test against? We've heard of (String.IsNullOrEmpty(value)).
  • What would be the best way to express this in the language, in terms of operators, keywords?

推荐答案

我个人会避免操作员的短路,只是让方法将其链接起来:

personally I'd avoid the short circuit from operators and just let the methods chain it:

public static int CompareChain<T>(this int previous, T a, T b)
{
    if (previous != 0)
        return previous;
    return Comparer<T>.Default.Compare(a,b);
}

使用方式如下:

int a = 0, b = 2;
string x = "foo", y = "bar";
return a.Compare(b).CompareChain(x,y);

可以由JIT内联,因此它可以执行和内置于语言中的短路一样的功能,而不会带来更多的复杂性.

can be inlined by the JIT so it can perform just as well as short circuiting built into the language without messing about with more complexity.

响应您的询问,上述结构"是否可以不仅适用于比较,还可以,它可以通过选择是否由用户进行明确和可控制来适用.这从本质上讲更加复杂,但是操作更加灵活,因此这是不可避免的.

In response to your asking whether the above 'structure' can apply to more than just comparisons then yes it can, by making the choice of whether to continue or not explict and controllable by the user. This is inherently more complex but, the operation is more flexible so this is unavoidable.

public static T ElseIf<T>(
    this T previous, 
    Func<T,bool> isOK
    Func<T> candidate)
{
    if (previous != null && isOK(previous))
        return previous;
    return candidate();
}

然后像这样使用

Connection bestConnection = server1.GetConnection()
    .ElseIf(IsOk, server2.GetConnection)
    .ElseIf(IsOk, server3.GetConnection)
    .ElseIf(IsOk, () => null);

这是最大的灵活性,因为您可以在任何阶段更改 IsOk 检查,并且完全是懒惰的.对于在每种情况下OK校验都相同的情况,您可以像这样简化并完全避免使用扩展方法.

This is maximum flexibility in that you can alter the IsOk check at any stage and are entirely lazy. For situations where the is OK check is the same in every case you can simplify like so and entirely avoid extensions methods.

public static T ElseIf<T>(        
    Func<T,bool> isOK
    IEnumerable<Func<T>[] candidates)
{
   foreach (var candidate in candidates)
   { 
        var t = candidate();
        if (isOK(t))
            return t;
   }
   throw new ArgumentException("none were acceptable");
}

您可以使用linq做到这一点,但是这种方式会给出一个不错的错误消息并允许

You could do this with linq but this way gives a nice error message and allows this

public static T ElseIf<T>(        
    Func<T,bool> isOK
    params Func<T>[] candidates)
{
    return ElseIf<T>(isOK, (IEnumerable<Func<T>>)candidates);
}

样式可导致如下所示的易读代码:

style which leads to nice readable code like so:

var bestConnection = ElseIf(IsOk,
    server1.GetConnection,
    server2.GetConnection,
    server3.GetConnection);

如果要允许使用默认值,则:

If you want to allow a default value then:

public static T ElseIfOrDefault<T>(        
    Func<T,bool> isOK
    IEnumerable<Func<T>>[] candidates)
{
   foreach (var candidate in candidates)
   { 
        var t = candidate();
        if (isOK(t))
            return t;
   }
   return default(T);
}

显然,以上所有内容都可以使用lambda轻松编写,因此您的具体示例为:

Obviously all the above can very easily be written using lambdas so your specific example would be:

var bestConnection = ElseIfOrDefault(
    c => c != null && !(c.IsBusy || c.IsFull),
    server1.GetConnection,
    server2.GetConnection,
    server3.GetConnection);

这篇关于操作方法:短路倒置三元运算符,例如C#?有关系吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆