In a previous article I wrote how to parse Roman Numerals using C#. This article will focus on how to calculate with the class in an intuitive way. It will show how to implement implicit casting and the add and subtraction operator overloads. Fun stuff that’s probably useful in other projects.

It would be great to do stuff like this:

RomanNumeral X = "X";
string result = X + "IV" + 8;

Implement implicit casting

The first thing we’ll need to implement is implicit casting. This will enable the class to interact with strings and integers without having to cast them to a RomanNumeral first. Let’s look at the code:

public static implicit operator int(RomanNumeral r)
{
    return (r?.Number).GetValueOrDefault();
}

public static implicit operator RomanNumeral(int r)
{
    return new RomanNumeral(r);
}

public static implicit operator string(RomanNumeral r)
{
    return r?.ToString();
}

public static implicit operator RomanNumeral(string r)
{
    return Parse(r);
}

What are the drawbacks of this method? Well, theĀ Parse might return aĀ null when the string is not parsable (l33t is not a valid Roman Numeral). This might result in a null-reference exception. The constructor method will throw an exception when anything below 0 is passed. This is something you might want to work around.

Plus and minus operator overloading

Now let’s implement the arithmetical operators +, ,Ā /,Ā * andĀ %Ā for theĀ RomanNumeral class. Notice that negative numbers are not supported in this example. We’ll default to 0 (orĀ nulla as the Romans would call it).

public static RomanNumeral operator +(RomanNumeral r1, RomanNumeral r2)
{
    return r1?.Number + r2?.Number;
}

public static RomanNumeral operator -(RomanNumeral r1, RomanNumeral r2)
{
    var n = r1?.Number - r2?.Number;

    if (n < 0)
    {
        n = 0;
    }

    return new RomanNumeral(n.GetValueOrDefault());
}

public static RomanNumeral operator /(RomanNumeral r1, RomanNumeral r2)
{
    return r1?.Number / r2?.Number;
}

public static RomanNumeral operator *(RomanNumeral r1, RomanNumeral r2)
{
    return r1?.Number * r2?.Number;
}

public static RomanNumeral operator %(RomanNumeral r1, RomanNumeral r2)
{
    return r1?.Number % r2?.Number;
}

Because we’ve implemented implicit conversions first the class handles operation on strings and integers automagically:

RomanNumeral I = "I";
RomanNumeral IV = "IV";

int a = IV - 1;
int b = 4 - I;
int c = IV - "I";
int d = "IV" - I;
int e = IV - I;

Assert.AreEqual(3, a);
Assert.AreEqual(3, b);
Assert.AreEqual(3, c);
Assert.AreEqual(3, d);
Assert.AreEqual(3, e);

string f = IV - 1;
string g = 4 - I;
string h = IV - "I";
string i = "IV" - I;
string j = IV - I;

Assert.AreEqual("III", f);
Assert.AreEqual("III", g);
Assert.AreEqual("III", h);
Assert.AreEqual("III", i);
Assert.AreEqual("III", j);

RomanNumeral k = IV - 1;
RomanNumeral l = 4 - I;
RomanNumeral m = IV - "I";
RomanNumeral n = "IV" - I;
RomanNumeral o = IV - I;

Assert.AreEqual("III", k.ToString());
Assert.AreEqual("III", l.ToString());
Assert.AreEqual("III", m.ToString());
Assert.AreEqual("III", n.ToString());
Assert.AreEqual("III", o.ToString());

Beautiful, I say!

Comparison operators

Mathematical operations are one thing, but how about comparing Roman Numerals? Implementing anĀ IComparable andĀ IComparable<RomanNumeral> will allow sorting mechanisms to handle the class.

public int CompareTo(RomanNumeral other)
{
    if (object.ReferenceEquals(other, null))
    {
        return 1;
    }

    return Number.CompareTo(other.Number);
}

public int CompareTo(object obj)
{
    return CompareTo(obj as RomanNumeral);
}

protected static int Compare(RomanNumeral r1, RomanNumeral r2)
{
    if (object.ReferenceEquals(r1, r2))
    {
        return 0;
    }
    if (object.ReferenceEquals(r1, null))
    {
        return -1;
    }
    return r1.CompareTo(r2);
}

Notice how I’m not using theĀ == or the != operators. This will prevent infinite loops when we implement these operators using the compare methods. TheĀ object.ReferenceEquals will do the job.

Implementing the operator overloads

Now let’s implement theĀ ==,Ā !=,Ā <,Ā <=,Ā >,Ā >= operators using theĀ statisĀ Compare method.

public static bool operator ==(RomanNumeral r1, RomanNumeral r2)
{
    return Compare(r1, r2) == 0;
}

public static bool operator !=(RomanNumeral r1, RomanNumeral r2)
{
    return Compare(r1, r2) != 0;
}

public static bool operator <(RomanNumeral r1, RomanNumeral r2)
{
    return (Compare(r1, r2) < 0);
}

public static bool operator >(RomanNumeral r1, RomanNumeral r2)
{
    return (Compare(r1, r2) > 0);
}

public static bool operator <=(RomanNumeral r1, RomanNumeral r2)
{
    return (Compare(r1, r2) <= 0);
}

public static bool operator >=(RomanNumeral r1, RomanNumeral r2)
{
    return (Compare(r1, r2) >= 0);
}

Implement equals

The equality method can also be implemented using the CompareTo method. Remember that theĀ GetHashCode should be overridden as well.

public override bool Equals(object obj)
{
    return CompareTo(obj) == 0;
}

public override int GetHashCode()
{
    return this.Number.GetHashCode();
}

Summary

Iā€™ve shown how one can do arithmetic using Roman Numerals. Implicit casting and operator overloading are very helpful in this case. You canĀ download the class from GitHubĀ and use it in your projects.