C#中的false运算符有什么作用?

108

C#中有两个奇怪的操作符:

如果我理解正确,这些操作符可以在我想要使用类型而不是布尔表达式,并且我不想提供到bool的隐式转换的情况下使用。

假设我有以下类:

    public class MyType
    {
        public readonly int Value;

        public MyType(int value)
        {
            Value = value;
        }

        public static bool operator true (MyType mt)
        {
            return  mt.Value > 0;
        }

        public static bool operator false (MyType mt)
        {
            return  mt.Value < 0;
        }

    }

所以我可以编写以下代码:

    MyType mTrue = new MyType(100);
    MyType mFalse = new MyType(-100);
    MyType mDontKnow = new MyType(0);

    if (mTrue)
    {
         // Do something.
    }

    while (mFalse)
    {
        // Do something else.
    }

    do
    {
        // Another code comes here.
    } while (mDontKnow)

然而,在上述所有示例中,只有true运算符被执行。那么C#中的false运算符有什么作用呢?

注意:更多示例可以在这里这里这里找到。


现代文档可以在https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/false-operator找到。文档建议自C# 2.0添加可空类型以来,不再需要定义此运算符。 - Mark Amery
5个回答

66

您可以使用它来覆盖&&||运算符。

&&||运算符不能被覆盖,但是如果您以恰当的方式覆盖|&truefalse,编译器将在您编写||&&时调用|&

例如,看看这段代码(来自http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading-我从中了解到这个技巧;由@BiggsTRC存档):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new AndExpression(lhs, rhs);
}

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new OrExpression(lhs, rhs);
}

public static bool operator false(AbstractCriterion criteria)
{
       return false;
}
public static bool operator true(AbstractCriterion criteria)
{
       return false;
}

显然这是一种副作用,而不是它预期的使用方式,但它很有用。


你的链接是404。不确定你想如何编辑它,所以我将其保持不变。 - user7116
我更新了URL,使用存档副本,以便仍然可以阅读。 - IAmTimCorey

29

Shog9和Nir: 感谢您的答案。这些答案指引我阅读Steve Eichert 文章, 并且它又引导我阅读msdn

操作x && y被评估为T.false(x) ? x : T.&(x, y),其中T.false(x)是在T中声明的false运算符的调用,T.&(x, y)是所选运算符&的调用。换句话说,首先计算x并对结果调用false运算符以确定x是否明确为false。然后,如果x明确为false,则操作的结果是先前为x计算的值。否则,将计算y,并调用所选的&运算符,以在先前为x计算的值和为y计算的值之间产生操作的结果。


我想知道为什么他们没有选择使用(!T.true(x)) ? x : T.&(x, y)逻辑。 - Des Nerger

14

该链接页面http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx解释了它们的作用,即在可空值类型引入之前,它们是处理可空布尔值的一种方式。

我猜现在它们对于与ArrayList类似的东西都是没有用的 - 也就是绝对没什么用处。


7
据我所知,它通常用于对错误进行测试,例如当使用&&运算符时。请记住,&&会短路,因此在表达式中......(后面省略)
if ( mFalse && mTrue) 
{
   // ... something
}

调用 mFalse.false() 后,如果返回 true,则表达式将简化为调用 'mFalse.true()'(然后应该返回 false,否则会出现奇怪的事情)。
请注意,必须实现 & 运算符才能编译该表达式,因为它在 mFalse.false() 返回 false 时使用。

3
从您提供的MSDN文章中可以看出,这个方法是在C#2之前引入的,是为了支持可空布尔类型(例如int?、bool?等)。因此,您需要存储一个内部值来表示该值是true、false还是null。例如,在您的示例中,>0表示true,<0表示false,==0表示null,然后您就可以获得SQL风格的null语义。您还需要实现一个.IsNull方法或属性,以便能够明确地检查nullity。
与SQL进行比较,假设有一个名为Table的表,其中3行的Foo值为true,3行的Foo值为false,另外3行的Foo值为null。
SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE
6

为了统计所有行,您需要按照以下步骤进行操作:-
SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL
9

这个“IS NULL”语法在您的类中的等效代码是.IsNull()。
LINQ 使与 C# 的比较更加清晰:-
int totalCount = (from s in MyTypeEnumerable
                 where s || !s
                 select s).Count();

假设MyTypeEnumberable的内容与数据库完全相同,即3个值等于true,3个值等于false,3个值等于null。在这种情况下,totalCount将会评估为6。但是,如果我们重写了代码如下:
int totalCount = (from s in MyTypeEnumerable
                 where s || !s || s.IsNull()
                 select s).Count();

然后totalCount将评估为9。
在链接的MSDN文章中给出的DBNull示例演示了BCL中具有这种确切行为的类。
实际上,结论是,除非您完全确定要使用此类型的行为,否则不应使用此选项,最好只使用更简单的可空语法!!
更新:我刚注意到您需要手动覆盖逻辑运算符!、||和&&以使其正常工作。我相信false运算符会进入这些逻辑运算符中,即指示真实性、虚假性或“其他”。如另一条评论中所述,!x不能立即起作用;您必须重载!。奇怪!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接