I've been searching for actual working code where an overloaded false
operator actually gets executed.
This question (What's the false operator in C# good for?) is somewhat the same, but the accepted answer links to an url which is returning a 404 error. I've also looked at How does operator overloading of true and false work? and some other questions.
What I've found in almost all answers is that false
only gets executed when you use a short circuited and like x && y
. This is evaluated as T.false(x) ? x : T.&(x, y)
.
Ok, so I have the following code. The struct
contains an int
and considers itself true if the int is greater than zero.:
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();
}
}
Now I would hope the following program will execute and use the overloaded false
operator.
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);
}
}
However, it does not even compile. It says it cannot apply operator '&&' to operands of type 'MyStruct' and 'MyStruct'.
I know I can implement an overload of the &
operator. So let's do that. The &
must return a MyStruct
, so I can not make it return a bool
.
public static MyStruct operator &(MyStruct lhs, MyStruct rhs) {
return new MyStruct(lhs._i & rhs._i);
}
Now the code does compile. Its output is 1
and -1
. So the result of b1 && b2
is not the same as that of b2 && b1
.
If I debug the code, I see that b1 && b2
first executes the false
operator on b1
, which returns false
. Then it performs the &
operator on b1 and b2, which performs a bitwise and on 1 and -1, resulting in 1. So it indeed is first checking if b1 is false.
The second expression, b2 && b1
first executes the false
operator on b2
, which returns true
. Combined with the fact I'm using short circuiting, it doesn't do anything with b1
and just prints out the value of b2
.
So yes, the false
operator is executed when you use short circuiting. However, it does not execute the true
or false
operator on the second argument, but instead executes the overloaded &
operator on the operands.
When can this ever be useful? Or how can I make my type so that it can check if the two variables both are true?
The contents of the URL you mentioned that was 404 can be found here:
http://web.archive.org/web/20080613013350/http://www.ayende.com/Blog/archive/2006/08/04/7381.aspx
The article that the author is referring to is here:
http://web.archive.org/web/20081120013852/http://steve.emxsoftware.com/NET/Overloading+the++and++operators
To avoid the same issue again, here is the highlights from the article:
A couple months ago I posted about our query API along with an explanation of how it works. Our query API allows us to express our queries using strongly typed C# syntax:
List<Customer> customers = repository.FindAll(Customer.Columns.Age == 20 & Customer.Columns.Name == “foo”);
One of the things I pointed out in my previous posts was that I couldn’t overload the && and || operators directly since the framework doesn’t allow such craziness…at least not directly.
In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ?:, checked, unchecked, new, typeof, as, and is operators. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/vclrfcsharpspec_7_2_2.asp
Over the last month I’ve done a little investigation on the topic to see if and how I can get && and || to behave the way I want. This evening I came across the Conditional logical operators page on MSDN which gave me the answer I was looking for:
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. The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x, y) is an invocation of the selected operator |. In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Then, if x is definitely true, 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. Since we already have the & and | operators in place it was simply a matter of overloading the true and false operators to both return false. This results in the & and | operators always being called which in turn results in the two criteria objects being turned into an AndCriteria/OrCriteria!
So now we can express our criteria expressions using the && and || syntax we’re accustomed to.
repository.FindAll(Customer.Columns.Age == 20 && Customer.Columns.Name == “foo”);
repository.FindAll(Customer.Columns.FirstName == “Foo” || Customer.Columns.LastName == “Bar”);
The relevant operator overloads are shown below.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With