Should wrappers exhibit reference equality when they wrap the same object?

by John Wu   Last Updated September 10, 2019 23:05 PM

I'm writing a wrapper for XML elements that allows a developer to easily parse attributes from the XML. The wrapper has no state other than the object being wrapped.

I am considering the following implementation (simplified for this example) which includes an overload for the == operator.

class XmlWrapper
{
    protected readonly XElement _element;

    public XmlWrapper(XElement element)
    {
        _element = element;
    }

    public string NameAttribute
    {
        get
        {
            //Get the value of the name attribute
        }
        set
        {
            //Set the value of the name attribute
        }
    }

    public override bool Equals(object other)
    {
        var o = other as XmlWrapper;
        if (o == null) return false;
        return _element.Equals(o._element);
    }

    public override int GetHashCode()
    {
        return _element.GetHashCode();
    }

    static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
    {
        if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
        if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;

        return lhs._element == rhs._element;
    }

    static public bool operator != (XmlWrapper lhs, XmlWrapper rhs)
    {
        return !(lhs == rhs);
    }
}

As I understand idiomatic c#, the == operator is for reference equality while the Equals() method is for value equality. But in this case, the "value" is just a reference to the object being wrapped. So I am not clear what is conventional or idiomatic for c#.

For example, in this code...

var underlyingElement = new XElement("Foo");
var a = new XmlWrapper(underlyingElement);
var b = new XmlWrapper(underlyingElement);

a.NameAttribute = "Hello";
b.NameAttribute = "World";

if (a == b)
{
    Console.WriteLine("The wrappers a and b are the same.");
}

....should the program output "The wrappers a and b are the same" ? Or would that be odd, i.e. violate the principal of least astonishment?

Tags : c# .net operators


Answers 2


If the convention states == should compare references then any overload of it goes against the convention. Whether or not prefering a conventional design rather than a specific one is a design choice that can be justified by some implementation need.

However, it is hard to advocate in favor of overloading operators other than implementing idiomatic unambiguous operations (such as adding two complex numbers) because of how tricky it can be to prevent and debug operator API misusage. I would expect that, if such operator is maintained, it would be for some obscure compatibility reason (e.g. after a codebase raw replace XElement by XMLWrapper, in case that make any sense...).

From a design standpoint, even if we are speaking of a marginal use case of the object, I would argue the program should definitely stay silent.

(Disclaimer : not expert of C#)

Arthur Havlicek
Arthur Havlicek
September 10, 2019 22:48 PM

You are basically comparing strings so I would be astonished if two wrappers containing the same XML content would not be considered equal, be it checked using Equals or ==.

The idiomatic rule may make sense for reference type objects in general but strings are special in an idiomatic sense, you are supposed to treat and regard them as values although technically they are reference types.

Your Wrapper postfix adds confusion though. It basically says "not an XML element". So should I treat it as a reference type after all? Semantically this would not make sense. I would be less confused if the class were named XmlContent. This would signal we care about content, not technical implementation details.

Martin Maat
Martin Maat
September 10, 2019 22:57 PM

Related Questions


Updated March 10, 2017 00:05 AM

Updated May 20, 2015 03:02 AM

Updated March 03, 2016 03:02 AM

Updated July 08, 2015 13:02 PM

Updated December 29, 2016 08:02 AM