Search code examples
c#castingtypecasting-operator

How to create 1 / 0 returning type for bool?


In C#, how it's possible to create custom type/cast for i.e. bool ? To better explain, i want that such expression:

bool cond=...;
int myVar=  cond as customType;

so, i want customType to behave as myVar become either 0 or 1, depending of cond (if true, then 1, else 0).

Is that possible?


please, don't offer me cond ? 1 : 0 solution or others. I asked exactly what I asked, so re-read (or analyze) it if before flagging.


Solution

  • Yes, you can do so. If you want a custom type that behaves like a built-in type, you must take care to override some methods inherited from System.Object. Also, you need conversion operators.

    Let's create a struct called Logical having an int property Value.

    public readonly struct Logical : IEquatable<Logical>
    {
        public Logical(int value)
        {
            Value = value == 0 ? 0 : 1;
        }
    
        public Logical(bool cond)
        {
            Value = cond ? 1 : 0;
        }
    
        public int Value { get; }
    
        ... conversions and overrides
    }
    

    It has 2 constructors, allowing you to build a value from either an int or bool.

    We can declare implicit conversions to convert between bool and Logical, int and Logical and Logical and bool.

    public static implicit operator Logical(bool cond) => new Logical(cond);
    
    public static implicit operator Logical(int i) => new Logical(i);
    
    public static implicit operator bool(Logical logical) => logical.Value != 0;
    

    It is also good to override Equals and GetHashCode to easily be able to compare values or to add them to dictionaries or hash sets.

    public bool Equals(Logical other) // Implements IEquatable<Logical>
    {
        return Value.Equals(other.Value);
    }
    
    public override bool Equals(object obj)
    {
        if (obj is Logical logical) {
            return Equals(logical);
        }
        return base.Equals(obj);
    }
    
    public override int GetHashCode() => Value.GetHashCode();
    

    If you override Equals, it is natural to overload == and !=

    public static bool operator ==(Logical a, Logical b) => a.Value == b.Value;
    public static bool operator !=(Logical a, Logical b) => a.Value != b.Value;
    

    Finally, we override ToString to be able to print Logicals.

    public override string ToString() => Value == 0 ? "FALSE" : "TRUE";
    

    Now, we can do these sort of things:

    double x = 3.14;
    Logical logical = x > 0.0;
    bool b = logical;
    
    Console.WriteLine($"logical = {logical}");
    Console.WriteLine($"b       = {b}");
    
    logical = -3;
    Console.WriteLine($"logical = {logical}");
    Console.WriteLine($"logical.Value = {logical.Value}");
    logical = 0;
    Console.WriteLine($"logical = {logical}");
    Console.ReadKey();
    

    It prints:

    logical = TRUE
    b       = True
    logical = TRUE
    logical.Value = 1
    logical = FALSE
    

    There is more you can do. System.Bool, for instance, implements IComparable, IComparable<bool>, IConvertible and IEquatable<bool>. It also has static Parse and TryParse methods. You could also overload other operators. See: Overloadable operators (Operator overloading, C# reference).