1

I wrote a validation attribute to make conditional Required's possible.

public class RequiredIfEqualsAttribute : RequiredAttribute
{
    private readonly string _otherProperty;
    private readonly object _value;

    public RequiredIfEqualsAttribute(string otherProperty, object value)
        : base()
    {
        this._otherProperty = otherProperty;
        this._value = value;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var valToCompare = validationContext.ObjectInstance.GetType().GetProperty(_otherProperty).GetValue(validationContext.ObjectInstance, null);
        if (valToCompare == _value)
        {
            return base.IsValid(value, validationContext);
        }
        return null;
    }
}

It's easy enough to use:

[EnumDataType(typeof(SomeEnum))]
[Required]
public SomeEnum SomeType { get; set; }

[RequiredIfEquals("SomeType", SomeEnum.A)]
public string A { get; set; }

[RequiredIfEquals("SomeType", SomeEnum.B)]
public string B { get; set; }

I've noticed something odd though. This line:

if (valToCompare == _value)

will actually evaluate to false, even if valToCompare and _value both represent SomeEnum.A.

Is it because _value is readonly? When I use the following everything works as expected:

if (valToCompare.Equals(_value))

In this case, if valToCompare and _value both represent SomeEnum.A, the statement will evaluate to true, as it should.

Who can enlighten me?

Korijn
  • 1,383
  • 9
  • 27
  • In C#, `==` and `Equals()` are not the same, and each operator can be overriden to have different logic. However, usually `==` means reference equality, and Equals() means value equality. – SF Lee Sep 22 '14 at 09:38

1 Answers1

3

valToCompare and _value are statically typed as object. This means, that during == operator, only the referece equality will be checked, just like for any ordinary object.

.Net does not know (nor check) if those objects are special in any way. Even if you'd override the operator==, the .Net would not invoke it, becase the type of the variable is just "object". It would still use the most basic operator== that checks for reference equality (and for structs, the value equality..).

On the other hand, when you call Equals method, which is virtual btw, everything works, because your equality checks are executed. In fact, you ordered them explicitely to be executed. Just like any overridden virtual method from base class.

btw2. In case of null in valToCompare, you should use object.Equals(valToCompare, _value) which will not throw NullReferenceException.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107