C#中的错误运算符有什么用?

时间:2020-03-05 18:44:39  来源:igfitidea点击:

C#中有两个奇怪的运算符:

  • 真正的运营商
  • 错误的运算符

如果我理解正确,可以将这些运算符用于我要使用的类型,而不是布尔表达式,并且在这些类型中,我不想为布尔提供隐式转换。

假设我有以下课程:

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运算符。那么Cgood中的错误运算符有什么用呢?

注意:更多示例可以在此处,此处和此处找到。

解决方案

回答

我们链接到http://msdn.microsoft.com/zh-cn/library/6x6y6z4d.aspx的页面上说明了它们的作用,这是在引入可空值类型之前处理可空布尔的一种方法。

我想现在它们对于与ArrayList相同的东西很有用,即绝对没有。

回答

在我们链接到它的MSDN文章中,它似乎是在允许将Nullable(即int?,bool?等)类型引入C#2语言之前允许使用可为空的布尔类型。因此,我们将存储一个内部值,指示该值是true还是false或者null,即在示例中> 0表示true,<0表示false和== 0表示null,然后我们将获得SQL样式的null语义。我们还必须实现.IsNull方法或者属性,以便可以显式检查无效性。

与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使与Ceven的比较更加清晰:

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中有关false运算符的文章中给出的DBNull示例演示了BCL中具有此确切行为的类。

实际上,结论是除非我们完全确定要这种行为,否则不应该使用此功能,最好只使用更简单的可为空的语法!

更新:我刚刚注意到我们需要手动覆盖逻辑运算符!,||和&&使其正常工作。我相信错误的运算符会影响这些逻辑运算符,即表明事实,虚假或者"否则"。正如在另一条评论中指出的那样,!x不会奏效。你必须超载!怪异的!

回答

AFAIK,它将用于测试是否为假,例如当&&运算符开始起作用时。请记住,&&短路,所以在表达式中

if ( mFalse && mTrue) 
{
   // ... something
}

调用了mFalse.false(),并在返回true时将表达式简化为对mFalse.true()的调用(然后应返回false,否则事情会变得很奇怪)。

请注意,我们必须实现运算符才能编译该表达式,因为如果mFalse.false()返回false时将使用该运算符。

回答

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

不能覆盖&&||运算符,但是如果以完全正确的方式覆盖|&&,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;
}

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

回答

Shog9和Nir:
感谢回答。这些答案使我想到了史蒂夫·艾希特(Steve Eichert)的文章,并指出了msdn:

The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Then, if x is definitely false, the result of the operation is the value previously computed for x. Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.