Comparing boxed value types

后端 未结 5 1011
轮回少年
轮回少年 2020-11-28 13:06

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 type

相关标签:
5条回答
  • 2020-11-28 13:41

    Since the input parameter's type is object, you will always get a boxed value inside the method's context.

    I think your only chance is to change the method's signature and to write different overloads.

    0 讨论(0)
  • 2020-11-28 13:42

    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.)

    0 讨论(0)
  • 2020-11-28 13:52

    I suppose

    I'd like to keep a simple reference comparison, unless the value is boxed.

    is somewhat equivalent to

    If the value is boxed, I'll do a non-"simple reference comparison".

    This means the first thing you'll need to do is to check whether the value is boxed or not.

    If there exists a method to check whether an object is a boxed value type or not, it should be at least as complex as that "overkill" method you provided the link to unless that is not the simplest way. Nonetheless, there should be a "simplest way" to determine if an object is a boxed value type or not. It's unlikely that this "simplest way" is simpler than simply using the object Equals() method, but I've bookmarked this question to find out just in case.

    (not sure if I was logical)

    0 讨论(0)
  • 2020-11-28 14:00

    How about this:

    if(object.ReferenceEquals(first, second)) { return; }
    if(first.Equals(second)) { return; }
    
    // they must differ, right?
    

    Update

    I realized this doesn't work as expected for a certain case:

    • For value types, ReferenceEquals returns false so we fall back to Equals, which behaves as expected.
    • For reference types where ReferenceEquals returns true, we consider them "same" as expected.
    • For reference types where ReferenceEquals returns false and Equals returns false, we consider them "different" as expected.
    • For reference types where ReferenceEquals returns false and Equals returns true, we consider them "same" even though we want "different"

    So the lesson is "don't get clever"

    0 讨论(0)
  • 2020-11-28 14:04

    Equals() is generally the preferred approach.

    The default implementation of .Equals() does a simple reference comparison for reference types, so in most cases that's what you'll be getting. Equals() might have been overridden to provide some other behavior, but if someone has overridden .Equals() in a class it's because they want to change the equality semantics for that type, and it's better to let that happen if you don't have a compelling reason not to. Bypassing it by using == can lead to confusion when your class sees two things as different when every other class agrees that they're the same.

    0 讨论(0)
提交回复
热议问题