在布尔表达式中使用空条件运算符的最佳方法


11

您正在编写一个布尔表达式,可能看起来像这样:

team.Category == "A Team" && team?.Manager?.IsVietnamVet

public class Manager
{
    public bool IsVietnamVet { get; set; }
}

public class Team
{
    public string Category { get; set; }

    public Manager Manager { get; set; }
}

...而您得到一个错误:

运算符'&&'不能应用于类型'bool'和'bool?'的操作数

最佳/最干净的处理方式是什么?

  1. team.Category == "A Team" && (team?.Manager?.IsVietnamVet ?? false)

    这真的可读吗?

  2. team.Category == "A Team" && (team?.Manager?.IsVietnamVet).GetValueOrDefault()

    它可能不适用于LINQ到实体...

  3. team.Category == "A Team" && team?.Manager?.IsVietnamVet == true

    您真的会if (condition == true)毫不犹豫地写吗?

还有其他选择吗?最终写出来更好吗?

  1. team.Category == "A Team" && team.Manager != null && team.Manager.IsVietnamVet

if(!(String.IsNullOrEmpty(team.Manager)&& condition))...
探听

1
@StevieV从一开始就应该是这样;)
Santhos

1
更仔细地看代码,空条件部分应该是team.Manager?.IsVietnamVet,即之后没有空条件部分team,因为已经不能了null
2013年

2
“您会毫不犹豫地真的写出if(condition == true)吗?” 对于普通布尔值,不可以,因为它是多余的。但是,对于null的布尔值,这是相关的。nullableBool == true基本上是在测试nullableBool != false && nullableBool != null(并且第二部分使它有用,因此不是多余的)
Flater 17/09/29

2
nullableBool == true如果不创建包装,我便开始使用。它是可读的,因为== true使用@Flater提到的常规布尔值时通常不写,因此建议该变量为可空值。另外,由于您不使用@Fabio提到的多个空条件,因此它提高了LINQ的可读性。
桑索斯岛,

Answers:


4

在这种特殊情况下,明智的做法是遵循Demeter定律,

public class Team
{
    public bool IsManagerVietnamVet => Manager?.IsVietnamVet ?? false;
}    

更一般而言,如果布尔表达式复杂或丑陋,那无话可说,您无法将其(或其中的一部分)划分为单独的语句:

bool isVietnamVet = Manager?.IsVietnamVet ?? false;

if (team.Category == "A Team" && isVietnamVet)

在调试器中单步执行代码时,将复杂的条件打包到一个命令中bool以节省一点鼠标悬停通常会更好。实际上,将整个内容放在一个bool变量中可能更好。

bool isVietnamVetAndCategoryA = (team.Category == "A Team"
    && Manager?.IsVietnamVet ?? false);

if (isVietnamVetAndCategoryA)

或使用LINQ:

var wibble = from flight in airport
             from passenger in flight.manifest
             let isOnPlane = 
                 (flight.FinishedBoarding && passenger.Flight == flight.FlightNumber)
             where !isOnPlane
             select passenger;

我想我主要倾向于这种解决方案。
桑索斯

1
新的C#语法可节省几行内容:public bool IsManagerVietnamVet =>(team.Category ==“”)&&(team.Manager?.IsVietnamVet ?? false);
格雷厄姆

请记住,长a && b && c &&...按顺序执行,如果前一个为,则下一个甚至不会执行false。因此人们通常在一开始就投入最快。将内容移动到单独的bool-var中时请记住这一点
jitbit,

@jitbit更多关于可维护性。诸如您所提到的那样的微优化通常是不必要的-除非性能被视为问题,并且性能分析表明进行此类更改会产生任何明显的影响,否则不必担心。
Ben Cottrell

@BenCottrell如果该IsManagerVietnamVet属性用于检查数据库,我将其称为“微”优化;)
jitbit

3

我想选择3(即== true)是测试最干净的方式,一个bool?true,因为它是关于它做什么很清楚。

在大多数代码x == true中,这是没有意义的,因为它与相同x,但是在这里并不适用,所以我认为== true不会很混乱。


1
我认为这绝对是我们要使用null条件运算符的方法,因为它也是linq安全的。问题是可读性是否良好。从我的角度来看,选择是在opt 3和opt 4之间,出于可读性原因,我会选择4而不是3,程序员的意图似乎也更加清晰。我将Ben Cottrell的答案标记为正确,因为我喜欢这种方法。如果我能标出两个答案,我会的。
桑索斯

1
@Santhos-关于“程序员的意图似乎更加清晰”。恕我直言,在这种情况下,程序员第一次看到a?.b == true他们会感到困惑,但是一旦他们掌握了正在做的事情,它就变成了一个易于阅读的习惯用法,比!= null在复杂表达式中间进行测试要好得多。与相同a?.b ?? false,它似乎已成为最受欢迎的解决方案,因为它与您在处理布尔型以外的其他类型时所键入的内容相匹配[尽管我不喜欢布尔型。对我来说,它读起来并不自然。我更喜欢== true]。
制造商史蒂夫(Steve)

3

扩展Ben Cottrell的答案,“空对象”模式可以进一步帮助您。

无需返回null团队/经理,而是提取ITeamIManager接口并返回有意义的替代实现:

public class NoManager : IManager
{
    public bool IsVietnamVet => false;
}

public class NoTeam : ITeam
{
    public bool ManagedByVietnamVet => false;

    public IManager Manager => new NoManager();
}

突然之间,您可以team.ManagedByVietnamVet安全地进行操作。

当然,这依赖于上游提供者为teamnull安全-但这可以通过适当的测试来确保。


-4

我写了一个简单的类,您可以使用:

 public class MyBool 
    {
        public bool? Value { get; set; }

        public MyBool(bool b)
        {
            Value = b;
        }

        public MyBool(bool? b)
        {
            Value = b;
        }

        public static implicit operator bool(MyBool m)
        {
            return m?.Value ?? false;
        }

        public static implicit operator bool?(MyBool m)
        {
            return m?.Value;
        }

        public static implicit operator MyBool(bool m)
        {
            return new MyBool(m);
        }

        public static implicit operator MyBool(bool? m)
        {
            return new MyBool(m);
        }

        public override string ToString()
        {
            return Value.ToString();
        }
    }

如果可靠,可以使用自定义类型。您可以将MyBool两者bool与进行比较Nullable<bool>


1
该站点是有关软件设计的问题,而不是有关如何使特定代码起作用的问题,因此,如果您认为这是最好的解决方案,那么您的答案应该着眼于为什么您认为像这样的类是最好的解决方案,而不是问题所在。实现它所需的确切代码。
Ixrec
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.