Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding Equals and comparing to string

Tags:

c#

equals

I've defined a C# class with a string member. For all intents an purposes, think of this class as being a subclass of string (except that's not allowed). I'm using it to represent a strongly typed string field that matches a specific format (I've simplified this significantly).

public class field
{
    private readonly string m_field;
    public field(string init_value)
    {
        //Check the syntax for errors
        if (CheckSyntax(init_value))
        {
            m_field = init_value;
        }
        else
        {
            throw new ArgumentOutOfRangeException();
        }
    }

    public override string ToString()
    {
        return m_field;
    }
}

Now, I want to be able to compare this class directly to any other string (object or literal). Therefore, I implemented the following in the class:

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }

    return this.m_field == obj.ToString();
}

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

public static bool operator ==(field x, Object y)
{
    if ((object)x == null && y == null)
    {
        return true;
    }
    else if ((object)x == null || y == null)
    {
        return false;
    }
    else
    {
        return (x.m_field == y.ToString());
    }
}

public static bool operator !=(field x, Object y)
{
    return !(x == y);
}

Now when I'm writing a unit test, depending on the order that I'm passing in the arguments to Assert.AreEqual, I get different results:

string valid = "Some String";
field target = new field(valid);
Assert.AreEqual(target, valid); // PASSES
Assert.AreEqual(valid, target); // FAILS

I'm assuming this is because in the first assert, it's calling field.Equals() and in the second it's calling String.Equals(). Obviously I'm approaching this from the wrong angle. Can anyone give me some insight?

One other thing. I can't use a struct here (value type) because in my actual case I'm defining all this in a base class and inheriting from it.

like image 505
Scott Whitlock Avatar asked Dec 03 '22 15:12

Scott Whitlock


1 Answers

Basically you can't do what you want to - there's no way you can make string recognise your class for equality purposes. You'll never be able to make it reflexive - you'll never be able to make it obey the contract of object.Equals.

I would personally try to redesign it so that you didn't have the validation as part of the type itself - make it part of the relevant properties of the business entities (or whatever they are).

like image 185
Jon Skeet Avatar answered Dec 17 '22 15:12

Jon Skeet