1

I want to do some comparing of member properties at runtime but value type prohibits unusual behaviour.

I have something like the following

public static object DefaultValue(this Type type) 
{
    return type.IsValueType ? Activator.CreateInstance(type) : null;
}


class ExampleClass
{
    public string Id { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }

    public XElement ToXml()
    {
        var srcTree = from prop in GetType().GetProperties()
                      let value = prop.GetValue(foo, null)
                      where value != prop.PropertyType.DefaultValue()
                      select new XElement(prop.Name.ToLower(), value);

                              ...

    }
}

if I initialize my object new ExampleClass() I find the price with a value of 0. I can confirm DefaultValue() returns 0 for the price which is not equal to 0 during equality comparison. Is because now it’s comparing objects or what. What can I achieve the behaviour I want?

D-Shih
  • 44,943
  • 6
  • 31
  • 51
rethabile
  • 3,029
  • 6
  • 34
  • 68
  • What is the actual problem you're trying to solve? What you've shown us here is your proposed solution to your actual problem. – Robert Harvey Aug 25 '18 at 18:32
  • Are you trying to write your own serializer? – Parrish Husband Aug 25 '18 at 18:36
  • Maybe 0 != 0? https://stackoverflow.com/questions/5940222/how-to-properly-compare-decimal-values-in-c – Trap Aug 25 '18 at 18:38
  • 1
    `value != prop.PropertyType.DefaultValue()` do reference comparison. Each boxing operation for not nullable value type will return distinct references. You can use [`RuntimeHelpers.Equals`](https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.runtimehelpers.equals) instead. – user4003407 Aug 25 '18 at 18:44

1 Answers1

3
object DefaultValue(this Type type)

the method returns an object, Although you judge whether it is a value type in the method and use Activator.CreateInstance create the type dynamically.

but the value will be boxing in an object be an object type value instead of your expected value type.

When you used == on an expression of type object, it'll use ReferenceEquals to compare the references instead of value.

 var srcTree = from prop in GetType().GetProperties()
                          let value = prop.GetValue(foo, null)
                          where !Equals(value, prop.PropertyType.DefaultValue())
                          select new XElement(prop.Name.ToLower(), value); 

c# online


Here is a sample for your case

we can saw defaultVal object set a value 0, which is int type (doing boxing).

dymanicVal created int by Activator.CreateInstance method.

Then when we use == to compare two objects they will compare their reference instead of int value

so you can try to use Equals method to compare the value will call RuntimeHelpers.Equals method then compare their value instead of references.

object defaultVal = 0;
object dymanicVal = Activator.CreateInstance(typeof(int));

Console.WriteLine(Equals(defaultVal, dymanicVal)); //True
Console.WriteLine(defaultVal == dymanicVal);      //false

c# online

D-Shih
  • 44,943
  • 6
  • 31
  • 51