重载的false操作符什么时候被执行,它有什么好处

本文关键字:什么 执行 false 操作符 什么时候 重载 | 更新日期: 2023-09-27 18:00:31

我一直在搜索实际的工作代码,其中实际执行了重载的false运算符。

这个问题(C#中的假运算符有什么用?)有点相同,但接受的答案链接到一个返回404错误的url。我还研究了运算符如何重载真和假工作?以及其他一些问题。

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

好的,我有下面的代码。struct包含一个int,并且如果int大于零,则认为自己为true

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);
    }
}

然而,它甚至不编译。它说它不能应用operator&amp;'到类型为"MyStruct"answers"MyStruct"的操作数。

我知道我可以实现&运算符的重载。所以让我们这样做吧。&必须返回MyStruct,所以我不能让它返回bool

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

现在代码已经编译完毕。其输出为1-1。因此CCD_ 14的结果与CCD_。

如果我调试代码,我会看到b1 && b2首先在b1上执行false运算符,该运算符返回false。然后,它对b1和b2执行&运算符,对1和-1执行逐位和,得到1。因此,它确实是首先检查b1是否为假。

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

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

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

重载的false操作符什么时候被执行,它有什么好处

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

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+++和++操作员

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

几个月前,我发布了我们的查询API,并解释了它的工作原理。我们的查询API允许我们使用强类型C#语法来表达我们的查询:

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

我在之前的帖子中指出的一件事是,我不能让&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;并按照我想要的方式行事。今天晚上,我在MSDN上看到了条件逻辑运算符页面,它给了我想要的答案:

操作x&amp;y被评估为T.false(x)?x:T&(x,y),其中T.false(x)是对在T中声明的运算符false的调用,并且T.&(x,y)是对所选运算符&的调用;。换句话说,首先计算x,并对结果调用运算符false,以确定x是否绝对为false。然后,如果x肯定是false,则运算的结果是之前为x计算的值;对先前为x计算的值和为y计算的值调用,以产生运算的结果。运算x||y被求值为T.true(x)?x:T.|(x,y),其中T.true(x)是对在T中声明的运算符true的调用,而T.|(x、y)是对所选运算符|的调用。换句话说,首先计算x,并对结果调用运算符true,以确定x是否绝对为true。然后,如果x绝对为真,则运算的结果是之前为x计算的值。否则,对y进行求值,并对之前为x和y计算的值调用所选运算符|,以产生运算的结果。既然我们已经有了&和|运算符,这只是一个重载true和false运算符以同时返回false的问题。这导致&和|运算符总是被调用,这反过来又导致两个条件对象变成AndCriteria/OrCriteria!

现在我们可以使用&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);
}

编辑-

阅读链接的文章,我得到了以下使用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();
    }
}

回答您的最后一个问题:"我如何制作我的类型,以便它可以检查这两个变量是否都为真?"-只需使用&运算符。&&的全部目的是短路,这样在不需要的时候就不会检查第二个参数。

看看这个:

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个实例是否为true),但您的&运算符在实现此目的时不正确。它根据二进制算术工作,当使用参数MyStruct(1)true)和MyStruct(-1)false)调用时,生成值为1MyStruct实例。所以它基本上是(true & false) == true。这就是为什么b1 && b2给出的结果与您的示例中的b2 && b1不同。基于此运算符的任何进一步的逻辑都将是不可预测的。&&的行为,它在中实现。NET在false&方面证实了这一点。

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

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

在C#2.0之前,true和false运算符用于创建用户定义的 与SqlBool等类型兼容的可为null的值类型。但是, 该语言现在提供了对可为null的值类型的内置支持,并且 只要可能,就应该使用它们,而不是重载true和 虚假运算符

如果您只想将对象求值为布尔值,请删除运算符true和运算符false重载,然后只使用布尔重载。

真/假运算符的目的是提供布尔逻辑语义,而不需要隐式转换为bool

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