【问题标题】:Combining null coalescing operator with a conditional将空合并运算符与条件相结合
【发布时间】:2021-03-11 10:46:27
【问题描述】:

我正在尝试将合并运算符与条件运算符结合起来。这不会编译,我想知道是否有办法绕过它而不写一堆 if 语句:

public static Setting GetSetting(this Account account, string key, bool newIfNull = true)
{
    return account.Settings
        .FirstOrDefault(x =>
            x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase)) ??
                newIfNull ? new Setting
                {
                    Key = key
                } : null
    };
}

这将是 if 语句的替代方案:

public static Setting GetSetting(this Account account, string key, bool newIfNull = true)
{
    var setting = account.Settings
        .FirstOrDefault(x =>
            x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase));

    if (setting != null)
    {
        return setting;
    }

    return newIfNull ? new Setting
    {
        Key = key
    } : null;
}

有什么建议吗?我也很好奇为什么如果有人知道它不能编译。

【问题讨论】:

  • 添加一些括号? thing ?? (cond ? t : f)
  • 你试过把??之后的所有东西都放在括号里吗?
  • 背后的逻辑是什么?
  • 请显示编译器错误以及您尝试解决的方法。
  • @canton7 将所有内容放在一行中并不总是一个好主意

标签: c#


【解决方案1】:

空合并运算符has higher precendence 比三元运算符。这意味着表达式:

thing ?? cond ? t : f

被绑定为:

(thing ?? cond) ? t : f

如果您想更改此设置,请使用用于解决每个优先级问题的相同工具:括号。

thing ?? (cond ? t : f)

在你的例子中:

public static Setting GetSetting(this Account account, string key, bool newIfNull = true)
{
    return account.Settings
        .FirstOrDefault(x =>
            x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase)) ??
                (newIfNull ? new Setting
                {
                    Key = key
                } : null)
    };
}

【讨论】:

  • 括号的用法很完美。谢谢。
  • (我确实在 10 分钟前在 cmets 中说过...)
  • 好吧,我猜你会得到更多的因果报应:)
【解决方案2】:

switch 表达式会更容易阅读:

var setting = account.Settings
       .FirstOrDefault(x =>x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase));

return setting switch {
    Setting s=>s,
    null when newIfNull =>new Setting { Key = key },
    _ => null
};

var setting = account.Settings
       .FirstOrDefault(x =>x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase));

return (setting,newIfNull) 
    switch 
    {
        (Setting s,_)=>s,
        (_,true)  => new Setting { Key = key },
        _ => null
    };

这可以放在一个表达式中,但我怀疑这个问题本身就表明单行并不总是一个好主意:

return account.Settings
       .FirstOrDefault(x =>x.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase))
       switch {
           Setting s=>s,
           null when newIfNull =>new Setting { Key = key },
           _ => null
};

出于学术目的,元组形式是

return ( newIfNull, account.Settings.FirstOrDefault(x =>x.Key.Equals(key, 
                         StringComparison.CurrentCultureIgnoreCase))
    )
    switch 
    {
        (_,Setting s)=>s,
        (true,_)  => new Setting { Key = key },
        _ => null
    };

【讨论】:

  • 我不知道其他任何人,但这比 OP 的版本要花大约 5 倍的时间来解析。我认为用(null, false) 替换_ 分支会有所帮助,但即便如此
  • @canton7 复制/粘贴错误。在任何情况下我都不会使用单个表达式,条件太长所以很容易出错。
猜你喜欢
  • 2019-03-01
  • 2015-03-27
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 2017-02-13
  • 2020-11-05
相关资源
最近更新 更多