什么时候重载的false运算符会被执行,它有什么用呢?

时间:2011-06-26 19:47:31

标签: c# operator-overloading

我一直在寻找实际工作代码,其中重载的false运算符实际上已被执行。

This question (What's the false operator in C# good for?)有点相同,但接受的答案会链接到返回404错误的网址。我还查看了How does operator overloading of true and false work?和其他一些问题。

我在几乎所有答案中都发现,false仅在您使用短路时执行x && y。这被评估为T.false(x) ? x : T.&(x, y)

好的,所以我有以下代码。 struct包含int,如果int大于零,则认为自己为真。:

public struct MyStruct {
    private int _i;

    public MyStruct(int i) {
        _i = i;
    }

    public static bool operator true(MyStruct ms) {
        return ms._i > 0;
    }

    public static bool operator false(MyStruct ms) {
        return ms._i <= 0;
    }

    public override string ToString() {
        return this._i.ToString();
    }
}

现在我希望以下程序能够执行并使用重载的false运算符。

class Program {
    private static void Main() {
        MyStruct b1 = new MyStruct(1); // to be considered true
        MyStruct b2 = new MyStruct(-1); // to be considered false

        Console.WriteLine(b1 && b2);
        Console.WriteLine(b2 && b1);
    }
}

然而,它甚至没有编译。它表示无法应用运营商'&amp;&amp;'到'MyStruct'和'MyStruct'类型的操作数。

我知道我可以实现&运算符的重载。所以,让我们这样做。 & 必须返回MyStruct,因此我无法返回bool

public static MyStruct operator &(MyStruct lhs, MyStruct rhs) {
    return new MyStruct(lhs._i & rhs._i);
}

现在代码编译了。其输出为1-1。因此b1 && b2的结果与b2 && b1的结果不同。

如果我调试代码,我会看到b1 && b2首先执行false上的b1运算符,该运算符返回false。然后它在b1和b2上执行&运算符,执行按位,在1和-1上执行,结果为1.所以它确实首先检查b1是否为假。

第二个表达式b2 && b1首先执行false上的b2运算符,该运算符返回true。结合我使用短路的事实,它对b1没有任何作用,只打印出b2的值。

是的,当您使用短路时,false运算符被执行。但是,它不会在第二个参数上执行truefalse运算符,而是在操作数上执行重载的&运算符。

这什么时候有用呢?或者我如何制作我的类型以便它可以检查这两个变量是否都是真的?

5 个答案:

答案 0 :(得分:5)

您提到的404的内容可以在这里找到:

http://web.archive.org/web/20080613013350/http://www.ayende.com/Blog/archive/2006/08/04/7381.aspx

作者所指的文章在这里:

http://web.archive.org/web/20081120013852/http://steve.emxsoftware.com/NET/Overloading+the++and++operators

为了避免再次出现同样的问题,以下是本文的重点:

  

几个月前,我发布了关于我们的查询API以及它是如何工作的解释。我们的查询API允许我们使用强类型C#语法表达我们的查询:

List<Customer> customers = repository.FindAll(Customer.Columns.Age == 20 & Customer.Columns.Name == “foo”);
  

我在之前的帖子中指出的一件事是我无法超载&amp;&amp;和||操作员直接因为框架不允许这样的疯狂......至少不是直接的。

     

特别是,不能重载成员访问,方法调用或=,&amp;&amp;,||,?:,checked,unchecked,new,typeof,as和is运算符。   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/vclrfcsharpspec_7_2_2.asp

     

在过去的一个月里,我对这个主题进行了一些调查,看看我是否以及如何获得&amp;&amp;和||表现我想要的方式。今天晚上我遇到了MSDN上的条件逻辑运算符页面,它给了我正在寻找的答案:

     

操作x&amp;&amp; y被评估为T.false(x)? x:T。&amp;(x,y),其中T.false(x)是在T中声明的运算符false的调用,而T.&amp;(x,y)是所选运算符&amp;的调用。换句话说,首先计算x并在结果上调用operator false以确定x是否肯定为false。然后,如果x肯定是假的,则操作的结果是先前为x计算的值。否则,评估y,并选择运算符&amp;在先前为x计算的值和为y计算的值上调用,以生成操作的结果。   操作x || y被评估为T.true(x)? x:T。|(x,y),其中T.true(x)是在T中声明的运算符true的调用,而T. |(x,y)是所选运算符|的调用。换句话说,首先计算x并在结果上调用operator true以确定x是否肯定为真。然后,如果x绝对为真,则操作的结果是先前为x计算的值。否则,将评估y,并选择运算符|在先前为x计算的值和为y计算的值上调用,以生成操作的结果。   因为我们已经拥有了&amp;和|运算符到位只是一个重载真假操作符的问题都返回false。这导致&amp;和|操作员总是被调用,这反过来会导致两个标准对象变成AndCriteria / OrCriteria!

     

现在我们可以使用&amp;&amp;和&amp;和||我们习以为常的语法。

repository.FindAll(Customer.Columns.Age == 20 && Customer.Columns.Name == “foo”);

repository.FindAll(Customer.Columns.FirstName == “Foo” || Customer.Columns.LastName == “Bar”);
  

相关的运算符重载如下所示。

public static bool operator true(Criteria<T> criteria) {
   return false;
}

public static bool operator false(Criteria<T> criteria) {
   return false;
}

public static Criteria<T> operator &(Criteria<T> lhs, Criteria<T> rhs) {
   return new AndCriteria<T>(lhs, rhs);
}

public static Criteria<T> operator |(Criteria<T> lhs, Criteria<T> rhs) {
   return new OrCriteria<T>(lhs, rhs);
}

答案 1 :(得分:4)

修改 -

阅读链接文章我能够得到以下输出,它使用了true和false运算符:

op false on 1
op & on 1 -1
op true on 1
op true on -1
FALSE
op false on -1
op true on -1
FALSE
op true on 1
op true on 1
TRUE
op true on -1
op & on -1 1
op true on -1
op true on 1
TRUE

使用代码:

class Program
{
    static void Main(string[] args)
    {
        MyStruct b1 = new MyStruct(1); // to be considered true
        MyStruct b2 = new MyStruct(-1); // to be considered false

        Console.WriteLine((b1 && b2) ? "TRUE" : "FALSE");
        Console.WriteLine((b2 && b1) ? "TRUE" : "FALSE");

        Console.WriteLine((b1 || b2) ? "TRUE" : "FALSE");
        Console.WriteLine((b2 || b1) ? "TRUE" : "FALSE");

        Console.ReadLine();
    }
}

public struct MyStruct
{
    private int _i;

    public MyStruct(int i)
    {
        _i = i;
    }

    public static bool operator true(MyStruct ms)
    {
        Console.WriteLine("op true on {0}", ms);
        return ms._i > 0;
    }

    public static bool operator false(MyStruct ms)
    {
        Console.WriteLine("op false on {0}", ms);
        return ms._i <= 0;
    }

    public static MyStruct operator &(MyStruct lhs, MyStruct rhs)
    {
        Console.WriteLine("op & on {0} {1}", lhs, rhs);

        if (lhs)
        {
            return rhs;
        }
        else
        {
            return new MyStruct(-1); //-1 is false
        }
    }

    public static MyStruct operator |(MyStruct lhs, MyStruct rhs)
    {
        Console.WriteLine("op & on {0} {1}", lhs, rhs);

        if (lhs)
        {
            return lhs;
        }
        else
        {
            return rhs;
        }
    }

    public override string ToString()
    {
        return this._i.ToString();
    }
}

当你说第一个代码无法编译时,我不确定你的意思,虽然它没有使用运算符true / false,我在2010 express中运行了以下代码并得到了输出:

op bool on 1
op bool on -1
False
op bool on -1
False
op bool on -1
op bool on 1
True
op bool on 1
True

代码:

class Program
{
    static void Main(string[] args)
    {
        MyStruct b1 = new MyStruct(1); // to be considered true
        MyStruct b2 = new MyStruct(-1); // to be considered false

        Console.WriteLine(b1 && b2);
        Console.WriteLine(b2 && b1);

        Console.WriteLine(b2 || b1);
        Console.WriteLine(b1 || b2);

        Console.ReadLine();
    }
}

public struct MyStruct
{
    private int _i;

    public MyStruct(int i)
    {
        _i = i;
    }

    public static bool operator true(MyStruct ms)
    {
        Console.WriteLine("op true on {0}", ms);
        return ms._i > 0;
    }

    public static bool operator false(MyStruct ms)
    {
        Console.WriteLine("op false on {0}", ms);
        return ms._i <= 0;
    }

    public static implicit operator bool(MyStruct ms)
    {
        Console.WriteLine("op bool on {0}", ms);
        return ms._i > 0;
    }

    public override string ToString()
    {
        return this._i.ToString();
    }
}

答案 2 :(得分:1)

来自Microsoft(http://msdn.microsoft.com/en-us/library/6292hy1k.aspx):

在C#2.0之前,使用true和false运算符创建用户定义的 与诸如SqlBool之类的类型兼容的可空值类型。然而, 该语言现在提供对可空值类型的内置支持,以及 只要有可能,你应该使用它们而不是重载true和 虚假运营商。

如果您只想将对象评估为布尔值,请删除operator true和operator false overload,然后使用bool重载。

答案 3 :(得分:1)

回答你的上一个问题:“我如何制作我的类型,以便它可以检查两个变量是否都是真的?” - 只需使用&运算符即可。 &&的重点是短路,因此在没有必要时不检查第二个参数。

检查出来:

Console.WriteLine(b1 & b2); // outputs 1
Console.WriteLine(b2 & b1); // outputs 1

您实际上缺少一个重要的位,它允许您使用MyStruct(&|)作为布尔值 - 隐式转换为bool

public static implicit operator bool(MyStruct ms) {
    return ms._i > 0;
}

这允许您使用MyStruct(也是运算符的结果):

if (b1 & b2)
    Console.WriteLine("foo");

最后,可能是最重要的,请注意:您的示例中的问题来自您要执行逻辑操作的事实(检查MyStruct的2个实例是否为{{ 1}}),但是为了这个目的,您的true运算符实现不正确。它在二进制算术方面起作用,当使用参数&MyStruct)和1({{1}调用时,产生值为MyStruct(1)的{​​{1}}实例}})。所以它基本上是true。这就是MyStruct(-1)在您的示例中提供与false不同的结果的原因。基于该运算符的任何其他逻辑将被破坏且不可预测。在(true & false) == trueb1 && b2方面以.NET实现的b2 && b1行为证实了这一点。

编辑:您希望能够将&&用作布尔值。您实现了运算符false&,并期望MyStructtrue在布尔逻辑方面工作。但是,您在二进制算术(在false字段上使用&&)实现||,这使得&的此实现与您期望的布尔逻辑不兼容({ {1}},对&布尔值的解释意味着int。现在,请考虑&通常不是逻辑运算符(它不返回(1 & -1) == 1) - 它是一个实现为(true & false) == false的短路。请注意,它会在您的案例中返回MyStruct,您根据其字段的值将其解释为&&bool。底线:您希望T.false(x) ? x : T.&(x, y)对两个操作数进行逻辑测试,但MyStruct的.NET实现使用您的true实现,它与布尔逻辑不兼容期望的。

答案 4 :(得分:0)

真/假运算符的意思是提供布尔逻辑语义而无需隐式转换为bool

如果允许将类型隐式转换为bool,则不再需要true / false运算符。但是,如果您只想显式转换或不转换,但仍希望将您的类型作为ifwhile表达中的条件,则可以使用truefalse运算符。