Let's say we have the following simple classes:
abstract class Abc { }
class Bcd : Abc { public int val; }
By default, the == operator on Bcd instances will return false in this example:
var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };
So, following the guidance here the == operator can be added to Bcd:
class Bcd : Abc
{
public int val;
public bool Equals(Bcd obj)
{
if (Object.ReferenceEquals(obj, null)) return false;
if (Object.ReferenceEquals(obj, this)) return true;
if (obj.GetType() != GetType()) return false;
return obj.val == val;
}
public override bool Equals(object obj) => Equals(obj as Bcd);
public override int GetHashCode() => val.GetHashCode();
public static bool operator ==(Bcd a, Bcd b)
{
if (Object.ReferenceEquals(a, null))
{
if (Object.ReferenceEquals(b, null)) return true;
return false;
}
return a.Equals(b);
}
public static bool operator !=(Bcd a, Bcd b) => !(a == b);
}
And now, the expression evaluates to true:
var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };
However, I may want to store instances of Bcd (and perhaps other instances of other subclasses of Abc) in variables typed as Abc:
Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };
Now, this of course will return false:
var result_2 = a == b;
One way to get the desired behaviour is to add equality methods to Abc as well (even though it is an abstract class):
abstract class Abc
{
public bool Equals(Abc obj)
{
if (obj is Bcd && this is Bcd) return (obj as Bcd) == (this as Bcd);
return false;
}
public static bool operator ==(Abc a, Abc b)
{
if (Object.ReferenceEquals(a, null))
{
if (Object.ReferenceEquals(b, null)) return true;
return false;
}
return a.Equals(b);
}
public static bool operator !=(Abc a, Abc b) => !(a == b);
}
Now the expression returns true:
Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };
var result_2 = a == b;
My question is, is adding the equality operator (and Equals method, != operator, etc.) to the abstract parent class Abc in the above way the recommended approach? It feels a little boilerplate-ish. Moreover, if Abc is subclassed again in the future, the Equals operator in Abc needs to be updated; this also feels a little odd.
Is there any recommended guide for this pattern?
Related
Following (incorrect/dangerous) code
class EvilClass
{
protected int x;
public EvilClass(int x)
{
this.x = x;
}
public override bool Equals(Object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
{
return false;
}
else
{
EvilClass p = (EvilClass)obj;
p.x = 42;
return (x == p.x);
}
}
public override int GetHashCode()
{
return (x << 2);
}
public override string ToString()
{
return String.Format("EvilClass({0})", x);
}
}
void Main()
{
var e1 = new EvilClass(1);
var e2 = new EvilClass(2);
var equals = e1.Equals(e2);
Console.WriteLine("{0}", e1.ToString());
Console.WriteLine("{0}", e2.ToString());
}
Output:
EvilClass(1)
EvilClass(42)
As you can see, call of e1.Equals(e2) modify e2. If we mark parameter as in compiler would not allow us to modify it.
Object.Equals() not suppose to change it's parameter - so why parameter is not in (input) parameter?
The most obvious reason is that in was introduced in C# 7.2, while object.Equals has been around since the very first version of .net.
The other reason is that it wouldn't actually change anything. in prevents from mutating the reference, not the actual object. If you try this:
public bool Equals2(in Object obj)
{
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
{
return false;
}
else
{
EvilClass p = (EvilClass)obj;
p.x = 42;
return (x == p.x);
}
}
Then the output will still be:
EvilClass(1)
EvilClass(42)
Motivation
I'm looking to implement IComparer<> in a similar way to the demo code below. Where Foo is the type of objects I need to compare. It does not implement IComparable, but I'm providing an IComparer class for each field so the user can elect to equate to instances based on one field value.
enum Day {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
class Foo {
public int Bar;
public string Name;
public Day Day;
}
Comparer classes are:
// Compares all fields in Foo
public class FooComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Bar == y.Bar && x.Name == y.Name && return x.Day == y.Day;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Bar
public class FooBarComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Bar == y.Bar;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Name
public class FooNameComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Name == y.Name;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Day
public class FooDayComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Day == y.Day;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
Question
I want to allow the user to be able to combine multiple Comparer types to evaluate two instances of Type Foo. I'm not sure how to do that.
Idea
What I came up with is something like this, where I AND the results of comparisons done by all comparers in the list:
bool CompareFoo(Foo a, Foo b, params IComparer[] comparers)
{
bool isEqual = true;
// Or the list and return;
foreach (var comparer in comparers)
{
isEqual = isEqual && comparer.Equals(x,y);
}
return isEqual;
}
Notes
My target .NET version is 4.5.
I may be stuck with C# 5.0.
Also, may be stuck with `MSBuild 12.0
This is my first time to use IComparer.
You can combine multiple IEqualityComparer<Foo> objects by defining an additional comparer that takes other comparers as constructor parameters:
public class CompositeFooComparer : IEqualityComparer<Foo>
{
private IEqualityComparer<Foo>[] comparers;
public CompositeFooComparer(params IEqualityComparer<Foo>[] comparers)
{
this.comparers = comparers;
}
public bool Equals(Foo x, Foo y)
{
foreach (var comparer in comparers)
{
if (!comparer.Equals(x, y))
{
return false;
}
}
return true;
}
public int GetHashCode(Foo obj)
{
var hash = 0;
foreach (var comparer in comparers)
{
hash = hash * 17 + (comparer.GetHashCode(obj));
}
return hash;
}
}
Then you can create and use it like this:
var fooA = new Foo
{
Bar = 5,
Day = Day.Fri,
Name = "a"
};
var fooB = new Foo
{
Bar = 5,
Day = Day.Fri,
Name = "b"
};
var barComparer = new FooBarComparer();
var dayComparer = new FooDayComparer();
var compositeComparer = new CompositeFooComparer(barComparer, dayComparer);
Console.WriteLine(compositeComparer.Equals(fooA, fooB)); // displays "true"
Another idea is to have a comparer that does know which fields will be compared, based on boolean parameters instead.
public class ConfigurableFooComparer : IEqualityComparer<Foo>
{
private readonly bool compareBar;
private readonly bool compareName;
private readonly bool compareDay;
public ConfigurableFooComparer(bool compareBar, bool compareName, bool compareDay)
{
this.compareBar = compareBar;
this.compareName = compareName;
this.compareDay = compareDay;
}
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (x == null || y == null)
{
return false;
}
if (compareBar && x.Bar != y.Bar)
{
return false;
}
if (compareName && x.Name != y.Name)
{
return false;
}
if (compareDay && x.Day != y.Day)
{
return false;
}
return true;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hash = 0;
if (compareBar)
{
hash = hash * 17 + obj.Bar.GetHashCode();
}
if (compareName)
{
hash = hash * 17 + (obj.Name == null ? 0 : obj.Name.GetHashCode());
}
if (compareDay)
{
hash = hash * 17 + obj.Day.GetHashCode();
}
return hash;
}
}
And then using it like this:
var barAndDayComparer = new ConfigurableFooComparer(compareBar: true, compareName: false, compareDay: true);
Console.WriteLine(barAndDayComparer.Equals(fooA, fooB));
It seems to me that what you are trying to achieve feels very similar to a Chain-of-responsibility.
So why don't you arrange all your Foo comparers in a chain-like structure and make the chain extensible so that new links can be added at run-time?
Here's is the idea:
the client will implement whatever Foo comparers it wants and all of them will be neatly arranged in a way that all of them will be called one by one and if anyone returns false then the whole comparison returns false!
Here's the code:
public abstract class FooComparer
{
private readonly FooComparer _next;
public FooComparer(FooComparer next)
{
_next = next;
}
public bool CompareFoo(Foo a, Foo b)
{
return AreFoosEqual(a, b)
&& (_next?.CompareFoo(a, b) ?? true);
}
protected abstract bool AreFoosEqual(Foo a, Foo b);
}
public class FooNameComparer : FooComparer
{
public FooNameComparer(FooComparer next) : base(next)
{
}
protected override bool AreFoosEqual(Foo a, Foo b)
{
return a.Name == b.Name;
}
}
public class FooBarComparer : FooComparer
{
public FooBarComparer(FooComparer next) : base(next)
{
}
protected override bool AreFoosEqual(Foo a, Foo b)
{
return a.Bar == b.Bar;
}
}
The idea of the FooComparer abstract class is having something like a chain manager; it handles the calling of the whole chain and forces its derived classes to implement the code to compare the Foo's, all while exposing the method CompareFoo which is what the client will use.
And how will the client use it? well it can do something like this:
var manager = new FooManager();
manager.FooComparer
= new FooNameComparer(new FooBarComparer(null));
manager.FooComparer.CompareFoo(fooA, fooB);
But it's cooler if they can register the FooComparer chain to the IoC Container!
Edit
This is a more simplistic approach I've been using for a while to custom compare things:
public class GenericComparer<T> : IEqualityComparer<T> where T : class
{
private readonly Func<T, object> _identitySelector;
public GenericComparer(Func<T, object> identitySelector)
{
_identitySelector = identitySelector;
}
public bool Equals(T x, T y)
{
var first = _identitySelector.Invoke(x);
var second = _identitySelector.Invoke(y);
return first != null && first.Equals(second);
}
public int GetHashCode(T obj)
{
return _identitySelector.Invoke(obj).GetHashCode();
}
}
public bool CompareFoo2(Foo a, Foo b, params IEqualityComparer<Foo>[] comparers)
{
foreach (var comparer in comparers)
{
if (!comparer.Equals(a, b))
{
return false;
}
}
return true;
}
And let the client do:
var areFoosEqual = CompareFoo2(a, b,
new GenericComparer<Foo>(foo => foo.Name),
new GenericComparer<Foo>(foo => foo.Bar))
It may be possible to adapt the GenericComparer to have multiple identity selector as to pass them all in a single lambda but we would also need to update its GetHashCode method to compute the HashCode correctly using all the identity objects.
You can achieve by something like this :
class Program
{
static bool CompareFoo(Foo a, Foo b, List<IEqualityComparer<Foo>> comparers)
{
return comparers.All(com => com.Equals(a, b));
}
static void Main(string[] args)
{
List<IEqualityComparer<Foo>> compares = new List<IEqualityComparer<Foo>>
{
new FooNameComparer(),
new FooBarComparer()
};
var test1 = CompareFoo(new Foo { Name = "aio", Bar = 10 }, new Foo { Name = "aio", Bar = 10 }, compares);
var test2 = CompareFoo(new Foo { Name = "Foo1", Bar = 10 }, new Foo { Name = "Foo2", Bar = 10 }, compares);
}
}
Note : you must consider all possible conditions in your compare classes, for example in "FooNameComparer" class the below code can become a bug :
return x.Name == y.Name;
because if the "Name" property of two classes pass null, null == null return true! the code should be :
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
if (string.IsNullOrEmpty(x?.Name) || string.IsNullOrEmpty(y?.Name))
return false;
return x.Name == y.Name;
}
I have the following code:
public enum ClassType
{
I,
II,
}
public enum LocationType
{
A,
B
}
public class Person
{
public LocationType LocType
{ get; set; }
public ClassType ClaType
{ get; set; }
public override bool Equals(object obj)
{
Person obPer = obj as Person;
if (obPer == null)
return false;
if (LocType != obPer.LocType)
return false;
if (ClaType != obPer.ClaType)
return false;
return true;
}
public override int GetHashCode()
{
return LocType.GetHashCode()^ClaType.GetHashCode();
}
}
static void Main(string[] args)
{
var p1 = new Person()
{
ClaType = ClassType.I,
LocType = LocationType.A
};
var p2 = new Person()
{
ClaType = ClassType.I,
LocType = LocationType.A
};
bool isEqual1 = p1.Equals(p2); //true
bool getHashCodeNum = p1.GetHashCode() == p2.GetHashCode(); //true
bool isEqual2 = p1 == p2; //false
}
I find that isEqual1=true, getHashCodeNum=true, but isEqual2=false.
I would expect that since I already override Equals and GetHashCode, then the operator == should automatically follow the behavior of Equals, but this is not so. Any reason?
An == is an operator. You can overload the == operator over two Persons as follows:
public class Person {
//..
public static bool operator == (Person a, Person b)
{
if (Object.ReferenceEquals(a,null) && Object.ReferenceEquals(b,null))
return true;
if (Object.ReferenceEquals(a,null) || Object.ReferenceEquals(a,null))
return false;
return a.LocType == b.LocType && a.ClaType != b.ClaType;
}
public static bool operator != (Person a, Person b)
{
return ! (a == b);
}
}
== and != are pairs: you need to implement != if you implement == and vice versa, otherwise you get the error:
error CS0216: The operator Person.operator ==(Person, Person) requires a matching operator != to also be defined
Now when you compare two Persons it should work. Mind however that you do not override equality operators, you overload them. So the compiler picks the == implementation (this is not done at runtime through a dynamic binding). As a result:
bool isEqual2 = p1 == p2; //true
bool isEqual3 = (object) p1 == p2; //false
bool isEqual4 = p1 == (object) p2; //false
bool isEqual5 = (object) p1 == (object) p2; //false
By default the == over two objects is reference equality so only if the two arguments are Persons here, we check whether the two persons are equivalent.
It is therefore probably better to use Equals(..) if you want to check equality with a dynamic binding.
How can I define whether and how a comparison operator is applied to operands of my type?
You implement the IComparable interface with the CompareTo method.
To use all of the operators, try this:
public sealed class Foo : IEquatable<Foo>, IComparable<Foo>
{
public static int Compare(Foo first, Foo second)
{
if (Object.ReferenceEquals(first, null))
return (Object.ReferenceEquals(second, null) ? 0 : -1);
return first.CompareTo(second);
}
public static bool operator==(Foo first, Foo second)
{
return Object.Equals(first, second);
}
public static bool operator!=(Foo first, Foo second)
{
return !Object.Equals(first, second);
}
public static bool operator<(Foo first, Foo second)
{
return Foo.Compare(first, second) < 0;
}
public static bool operator >(Foo first, Foo second)
{
return Foo.Compare(first, second) > 0;
}
public static bool operator <=(Foo first, Foo second)
{
return Foo.Compare(first, second) <= 0;
}
public static bool operator >=(Foo first, Foo second)
{
return Foo.Compare(first, second) >= 0;
}
private string bar;
public string Bar
{
//getter and setter
}
public bool Equals(Foo other)
{
if (Object.ReferenceEquals(other, null))
return false;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return true;
return String.Equals(this.foo, other.foo);
}
public int CompareTo(Foo other)
{
if (Object.ReferenceEquals(other, null))
return 1;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return 0;
return String.Compare(this.bar, other.bar);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Foo);
}
public override int GetHashCode()
{
return this.bar == null ? 0 : this.bar.GetHashCode();
}
}
A good tutorial on this: http://winsharp93.wordpress.com/2009/06/28/implementing-icomparablet-iequatablet-and-the-equality-members/
Since you know the interfaces IComparable, IEquatable needs to be implemented you can tell if two instances of yourClass are comparable by using this (example):
if (yourClass is IEquatable<T> && yourClass2 is IEquatable<T> && yourClass is IComparable<T> && yourClass2 is IComparable<T>) //T is the same type
{
yourClass <= yourClass2;
}
You can overload operators for your type, e.g.
public class MyComparable
{
public static bool operator <(MyComparable left, MyComparable right)
{
// other things...
}
Allows you to do this:
MyComparable c1 = // something
MyComparable c2 = // something
if (c1 < c2)
// something
(in such a case, it would probably make sense to implement IComparable<MyComparable> also.
A simple class that implements IComparable, IComparable<T>, IEquatable<T> and overrides object.Equals(object), object.GetHashCode() and the various "standard" operators ==, !=, >, <, >=, <=.
Note the use of object.ReferenceEquals(object, object) so as not to trigger StackOverflowException. This because we are overloading the == and != operators and basing them on MyClass.Equals(MyClass), so MyClass.Equals(MyClass) clearly can't use them. A common error is, in fact, inside the
bool Equals(MyClass other)
{
if (other == null)
{
}
}
Booooom! Can't do that. Because the if (other == null) will recursively call the other.Equals((MyClass)null). What you could do is: if (((object)other) == null), because in C# operators can't be virtual, so here we are using the == of the object class.
InnerEquals and InnerCompareTo are present so the null check mustn't be done twice if the Equals(object) or CompareTo(object) are called.
public class MyClass : IComparable<MyClass>, IComparable, IEquatable<MyClass>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return 1;
}
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return 1;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
throw new ArgumentException("obj");
}
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return 0;
}
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
public static bool operator==(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return a.Equals(b);
}
// The != is based on the ==
public static bool operator!=(MyClass a, MyClass b)
{
return !(a == b);
}
public static bool operator>(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return false;
}
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyClass a, MyClass b)
{
return b > a;
}
public static bool operator >=(MyClass a, MyClass b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyClass a, MyClass b)
{
return !(a > b);
}
}
And this one is the variant for struct types. A lot shorter, because nearly all the object.ReferenceEquals(object, object) are gone. Value types can't be null.
public struct MyStruct : IComparable<MyStruct>, IComparable, IEquatable<MyStruct>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyStruct other)
{
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyStruct other)
{
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerEquals(other);
}
public bool Equals(MyStruct other)
{
return this.InnerEquals(other);
}
private bool InnerEquals(MyStruct other)
{
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
// The != is based on the ==
public static bool operator ==(MyStruct a, MyStruct b)
{
return a.Equals(b);
}
public static bool operator !=(MyStruct a, MyStruct b)
{
return !(a == b);
}
public static bool operator >(MyStruct a, MyStruct b)
{
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyStruct a, MyStruct b)
{
return b > a;
}
public static bool operator >=(MyStruct a, MyStruct b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyStruct a, MyStruct b)
{
return !(a > b);
}
}
(how) can I Inherit from Boolean?
(Or make my class comparable to Boolean with '=' Operator)
class MyClass : Boolean
{
public MyClass()
{
this = true;
}
}
class Program
{
public Program()
{
MyClass myClass = new MyClass();
if(myClass == true)
//do something...
else
//do something else...
}
}
You can't. System.Boolean is a struct, and you can't derive from structs.
Now, why do you want to do so, exactly? What's the bigger purpose?
You could include an implicit conversion operator from your class to bool, but personally I wouldn't. I would almost always prefer to expose a property, so you'd write:
if (myValue.MyProperty)
... I think that keeps things clear. But if you could give us more of the real context, we may be able to give more concrete advice.
Simple example:
public class MyClass {
private bool isTrue = true;
public static bool operator ==(MyClass a, bool b)
{
if (a == null)
{
return false;
}
return a.isTrue == b;
}
public static bool operator !=(MyClass a, bool b)
{
return !(a == b);
}
}
somewhere in code you can compare your object with boolean value:
MyClass a = new MyClass();
if ( a == true ) { // it compares with a.isTrue property as defined in == operator overloading method
// ...
}
You can use an implicit conversion operator to have this code:
class MyClass {
public bool Value { get; set; }
public MyClass() {
Value = true;
}
public static implicit operator bool(MyClass m) {
return m != null && m.Value;
}
}
class Program {
public static void Main() {
var myClass = new MyClass();
if (myClass) { // MyClass can be treated like a Boolean
Console.WriteLine("myClass is true");
}
else {
Console.WriteLine("myClass is false");
}
}
}
It can be used as above:
if (myClass) ...
Or like this:
if (myClass == true) ...
while your example wouldnt work, you can do something similar for your own classes to test if one equals the values of another.
http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
public static bool operator ==(ThreeDPoint a, ThreeDPoint b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.x == b.x && a.y == b.y && a.z == b.z;
}
public static bool operator !=(ThreeDPoint a, ThreeDPoint b)
{
return !(a == b);
}
You can ("or make my class comparable..."), by overriding the == operator. I presume Jon Skeet overlooked that part of the question.
If you want to be able to use your value in 'if' statements, define operator true and operator false (along with the & and | operators if you want to use && and ||.) (VB equivalents)
To answer more, I would have to know what you're trying to do (in other words, why not just use bool directly?)