1

I want to do something like this question, but it isn't working as I'm expecting.

I have a list of an object's properties and their types, an unknown object, and a list of default value types that I want to ignore from the object.

public void GetOnlyNonDefault(object oObject, IgnoreValues ignoreValues)
{
    //properties is set beforehand
    for (int i = 0; i < properties.Count; i++)
    {
        object originalValue = 
            oObject
                .GetType()
                .GetProperty(properties[i].Name)
                .GetValue(oObject, null);

        //retrieving the default value I want to ignore for this property
        object ignoreValue = ignoreValues.GetDefaultOf(properties[i]);

        //Problem here

        //This doesn't work
        if (originalValue == ignoreValue) { continue; }

        //This works for nearly everything BUT enums
        if (ValueType.Equals(originalValue, ignoreValue)) { continue; }
    }
}

I've read from here that enums' default value is zero, and that's what I'm returning from GetDefaultOf when the type is an enum. How can I do a compare by values for all the value types including enums in the above code?

Edit: May be relevant, but the enums I'm using in the oObject class don't have any value set to 0, they all start at 1.

public enum UserStatus 
{
    Regular = 1, Manager = 2, Director = 3, Admin = 4
}

Edit²: Here's a basic version of the code I'm trying to do giving the results I'm experiencing: http://pastebin.com/rfJA9CGp

I can't really change the enums because that's the point of this code, I don't know what is the object at runtime nor it's properties, but I want to figure any values different from the defined default (the class IgnoreValues contains the default values for all value types).

I can't cast to int when it's an enum because then I'd ignore the case where an enum with 0 was actually defined in the code, so I'm looking for any way to compare the values.

Community
  • 1
  • 1
Danicco
  • 1,573
  • 2
  • 23
  • 49
  • 2
    when comparing `Objects you need to use the `.Equals` and not `==` try changing this line `if (originalValue == ignoreValue)` to this and see if it yields the expected results `if (originalValue.Equals(ignoreValue){ continue;}` – MethodMan Nov 10 '14 at 23:28
  • @DJKRAZE Gives the same results (false). That's the same as `Object.Equals()` isn't? `ValueType.Equals` is supposedly the same but suited for ValueTypes (which I think Enum is). – Danicco Nov 10 '14 at 23:31
  • as a side note, the property of object (PropertyInfo) will always be the same, so you can set a value outside the loop of `oObject.GetType().GetProperty()` instead of using reflection everytime. – Erik Philips Nov 10 '14 at 23:41
  • What does "this doesn't work" mean? Does it mean that the line throws an exception? Compares two values and even though they *look* equal, they aren't? Something else? – Jim Mischel Nov 10 '14 at 23:48
  • if you set a breakpoint on the line that's causing you trouble, what are the values of `originalValue` and `ignoreValue`, and how are they different than what you expected? – Rufus L Nov 10 '14 at 23:48
  • @JimMischel They return `false`, though both values are 0. I expected `true`. The same happens for all ValueTypes in this case unless I use the Object/ValueType.Equals method. – Danicco Nov 10 '14 at 23:49
  • What do you WANT the default of an Enum to be? If you can answer that, then you can change how your GetDefaultOf method works on Enums. – Rufus L Nov 10 '14 at 23:50
  • From what I've found, an enum's default value is `0`, even if the enum doesn't have a `0` value. I want to test it if it's the default state of any enum, just like the `.Equals()` functions does (compare their values). I can't cast the enum to int because then I'd be ignoring enums with 0, and I can't deal with enums because I can't compare them from values. – Danicco Nov 10 '14 at 23:53

1 Answers1

4

When operator == is given values statically typed to object, it does a raw reference comparison. Value types must be boxed when placed into a variable typed object (and when returned from reflection calls), so the comparison will always be false, since even equal values are boxed to two different instances.

One way to compare enums would be to unbox the values to an int:

        object foo1 = Foo.A;
        object foo2 = Foo.A;
        Console.WriteLine(foo1 == foo2);              // False
        Console.WriteLine((int) foo1 == (int) foo2);  // True

This code will fail when the variable does not hold something that can be unboxed to int, so extra care is required. In particular, if the enum's underlying type is not int (which can happen), it will also result in a runtime exception. So an alernative is Enum.Equals, which supports enums of different underlying types:

        object foo = Foo.A;
        if (foo.GetType().IsEnum)
            Console.WriteLine(Enum.Equals(foo, your-default-value));

Now that you've shown how you get the default value to compare to, I see what the problem is. You pass an integer 0 to Enum.Equals. The method is written in such a way that an integer is never equal to an enum value. Getting the default value is not totally obvious:

        object foo = Foo.A;
        object defaultEnumValue = Activator.CreateInstance(foo.GetType()))

        Enum.Equals(foo, defaultEnumValue);

You may have noticed that this is relatively arcane. This is because C# is not generally very nice when your code involves processing all the possible types there are. The types are meant to be determined at compile time, but of course that isn't possible when you're writing code that inspects arbitrary objects.

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • `Enum.Equals` also returns false for me for some reason, although I expected it to work like the ValueTypes' ones... is your result different? – Danicco Nov 10 '14 at 23:51
  • @Danicco I don't know what you're doing exactly, but here's a complete example that shows "True": http://pastebin.com/dC78PQvK – Roman Starkov Nov 10 '14 at 23:53
  • Here's a basic version of the example I'm trying to do. I think this helped me figure where the problem is, but still no solution: http://pastebin.com/rfJA9CGp – Danicco Nov 11 '14 at 00:03
  • That worked! I didn't even need the check for enum at the bottom, the first `ValueType.Equals` returned true, thank you! – Danicco Nov 11 '14 at 00:17