0

I'm playing around a bit with determining the default values of objects, based on the example here:

https://stackoverflow.com/a/3195792/1293496

This particular extension method was created for System.Type. What I was trying to accomplish was to make this even more generic, where I could do something like this:

int i = 3;
bool amIaDefaultValue = i.IsDefaultValue();

I would expect this to return true if i == 0 (the default value for an int), and false for all other instances.

Here is my initial attempt:

public static bool IsDefaultValue<T>(this T value)
{
    var t = typeof(T); // always comes back as object..?

    if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
    {
        return value.Equals(Activator.CreateInstance<T>());
    }
    else
    {
        var defaultValue = default(T);

        if (value == null)
            return defaultValue == null;
        else
            return value.Equals(defaultValue);
    }
}

On the plus side, I'm able to attach .IsDefaultValue() to any object. Unfortunately, the type of T always comes back as System.Object. I can get the correct type if I set it up this way:

var t = typeof(value);

But if the value happens to be null, I'll get an error straight away. Is there a good workaround for implementing an extension method like this? Or should I stick to the tried and tested route from the example?

Edit As pointed out by comments, it seems I oversimplified this a bit and missed the root of the problem. Here's what was actually calling my IsDefaultValue():

foreach (var imprintProperty in deltas.GetType().GetProperties())
{
    var value = imprintProperty.GetValue(deltas);
    if (!value.IsDefaultValue())
    {
        // get corresponding prop in programmable area
        var programmableProp = progarea.GetType().GetProperty(imprintProperty.Name);
        if (programmableProp != null)
            programmableProp.SetValue(progarea, value);
    }
}

And now it becomes obvious that .GetValue is always returning as System.Object. Uff.

Is it still possible to treat the object as its underlying type in the extension method? Sorry for the confusion with this.

Community
  • 1
  • 1
MadHenchbot
  • 1,306
  • 2
  • 13
  • 27
  • 4
    I do not see the behavior you are describing, invoking your method with `3.IsValueDefault()` and adding a `Console.WriteLine(t)` in your extension method produces the expected `System.Int32` on the console. `typeof(value)` in your method would be a compiler error as well. What are you not telling us? – Preston Guillot Sep 30 '13 at 23:22
  • I was also not able to reproduce "always getting object" as the type. – Travis J Sep 30 '13 at 23:33
  • 2
    When you're calling the method, are you _sure_ that the _design-time_ type of `i` is known as `int`? As in, you don't have something like: `object i = 3; bool amIaDefaultValue = i.IsDefaultValue();`? (and as an aside, arguably you may want to use `value.GetType()` (check for nulls!) anyway as if you pass in a value type as the base `object` _or_ pass it typed as an interface it's implementing you will get incorrect results as `default(T)` will return `null`) – Chris Sinclair Sep 30 '13 at 23:40
  • I didn't understand the question, but to verify that `something` has default value is not simpler something like `public static bool IsDefaultValue(this T value) { return value == null || value.Equals(default(T)); }`? – Alessandro D'Andria Oct 01 '13 at 15:10
  • @AlessandroD'Andria Normally, yes. The problem is that when I use reflection, GetValue returns T as System.Object. So even if my original type was an int, default(T) returns null instead of 0. – MadHenchbot Oct 01 '13 at 15:46
  • @ChrisSinclair You were correct, sir. I was using reflection and .GetValue, which always returned an object. In addition, I didn't realize how Nullable types get boxed, and that led to a number of other unfortunate discoveries. Thanks for leading me down the right path there. – MadHenchbot Oct 03 '13 at 18:43
  • @MadHenchbot: Given your update, AFAIK, since you don't know the type at compile-time, the only way would be to use reflection to treat the extension method like a plain old `static` method, grab its `MethodInfo`, and use the [`MakeGenericMethod`](http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.makegenericmethod.aspx) method to turn it into the generic equivalent. – Chris Sinclair Oct 03 '13 at 19:41
  • 1
    (cont) That's probably not a viable solution for you. Unless you need to check for interfaces implemented by a value type, I think you can simply check for `null` and return `true` always, otherwise do the value-type check as you're doing now. If it's a reference-type and the value is non-null, return `false`. If it's a value type, check it against the default instance. – Chris Sinclair Oct 03 '13 at 19:43

1 Answers1

0

Take a look at this:

static class Program
{
    static void Main()
    {
        int a = 1;

        Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());

        a = 0;

        Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());

        object obj = new object();

        Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());

        obj = null;

        Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());

        int? b = 1;

        Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());

        b = null;

        Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());

        Console.ReadKey(true);
    }

    static bool IsDefaultValue<T>(this T value)
    {
        if (ReferenceEquals(value, null))
        {
            return true;
        }

        var t = value.GetType();

        if (t.IsValueType)
        {
            return value.Equals(Activator.CreateInstance(value.GetType()));
        }

        return false;
    }
}

Apparently works (I've to say that I was convinced that the other way should have worked but not)

Alessandro D'Andria
  • 8,663
  • 2
  • 36
  • 32
  • For int? types, IsDefaultValue() returns true for 0 AND null. It should only return true for null. I'm getting the impression that Nullable types and generics don't play well together. – MadHenchbot Oct 01 '13 at 19:32