Search code examples
c#equalityboxingunboxing

Comparing boxed value types


Today I stumbled upon an interesting bug I wrote. I have a set of properties which can be set through a general setter. These properties can be value types or reference types.

public void SetValue( TEnum property, object value )
{
    if ( _properties[ property ] != value )
    {
        // Only come here when the new value is different.
    }
}

When writing a unit test for this method I found out the condition is always true for value types. It didn't take me long to figure out this is due to boxing/unboxing. It didn't take me long either to adjust the code to the following:

public void SetValue( TEnum property, object value )
{
    if ( !_properties[ property ].Equals( value ) )
    {
        // Only come here when the new value is different.
    }
}

The thing is I'm not entirely satisfied with this solution. I'd like to keep a simple reference comparison, unless the value is boxed.

The current solution I am thinking of is only calling Equals() for boxed values. Doing a check for a boxed values seems a bit overkill. Isn't there an easier way?


Solution

  • If you need different behaviour when you're dealing with a value-type then you're obviously going to need to perform some kind of test. You don't need an explicit check for boxed value-types, since all value-types will be boxed** due to the parameter being typed as object.

    This code should meet your stated criteria: If value is a (boxed) value-type then call the polymorphic Equals method, otherwise use == to test for reference equality.

    public void SetValue(TEnum property, object value)
    {
        bool equal = ((value != null) && value.GetType().IsValueType)
                         ? value.Equals(_properties[property])
                         : (value == _properties[property]);
    
        if (!equal)
        {
            // Only come here when the new value is different.
        }
    }
    

    ( ** And, yes, I know that Nullable<T> is a value-type with its own special rules relating to boxing and unboxing, but that's pretty much irrelevant here.)