tags:

views:

209

answers:

4

I want to be able to check whether a value is the default for its value type. Ideally, I'd like to say:

DoSomething<TValue>(TValue value) {
    if (value == default(TValue)) {
        ...
    }
}

However, the compiler complains that it can't do a == comparison on TValue and TValue. This is the best workaround that I've come up with so far:

DoSomething<TValue>(TValue value) {
    if (value == null || value.Equals(default(TValue))) {
        ...
    }
}

Is there a more elegant/correct way to go about this?

+3  A: 

Throw in the class constraint and it should work.

public void Test<T>(T instance) where T : class
{
    if (instance == default(T))
    {

    }
}

Or if you only want value types you can do this.

public void Test<T>(T instance) where T : struct, IEquatable<T>
{
    if (instance.Equals(default(T)))
    {

    }
}
ChaosPandion
If you throw in the `class` constraint you may as well just check against `null`...
Marc Gravell
@Marc - I know, at this point it is a matter of preference.
ChaosPandion
I am hoping to make this work for any type, including value and class types.
StriplingWarrior
+5  A: 
public bool EqualsDefaultValue<T>(T value)
{
    return EqualityComparer<T>.Default.Equals(value, default(T));
}
Bryan Watts
+1  A: 

Your problem is that a genric type (with no constraint) has to be "compilable" for any type. Since not all types have an == operator your code will not compile.

One way to resolve it is to add a class constraint however since your using default(TValue) that would suggest you want the code to work with other types. (otherwise just use null instead of default(TValue). One solution might be something similar to what Bryan Watts suggests

bool DoSomething<TValue>(TValue value) {
    return EqualityComparer<TValue>.Default.Equals(value, default(TValue));
}

or you could wrap it up in an extension method

bool IsDefault<TValue>(this TValue value) {
    return EqualityComparer<TValue>.Default.Equals(value, default(TValue));
}
Rune FS
A: 

Adding to the answers posted here, I think we should also be able to specify if you we want value or reference equality:

static public class MyGenericHelper
{
    static public bool EqualsByValue<T>(T x, T y)
    {
        return EqualityComparer<T>.Default.Equals(x, y);
    }

    static public bool EqualsByReference<T>(T x, T y)
    {
        if (x is ValueType) return EqualityComparer<T>.Default.Equals(x, y) // avoids boxing

        return Object.ReferenceEquals(x, y);
    }
}

We all just love to create and maintain a zillion little helper methods like that don't we :->

herzmeister der welten
Is seems like `typeof(T).IsValueType` would be preferable to `x is ValueType` both in terms of readability and performance. Am I wrong?
StriplingWarrior
Maybe readability is a matter of taste sometimes. :-> ... `x is ValueType` just intuitively "feels faster" for me, because `typeof(T).IsValueType` has to retrieve the quite heavy `Type` instance, and the Reflector reveals that the `.IsValueType` property calls a virtual method which implemented in `RuntimeType` ultimately calls something extern. But then who am I to judge, I'm not an insider. They might even compile down to the same instructions. Perhaps it's a good new question. ;-) ... Or you could do some performance tests yourself if it's crucial.
herzmeister der welten
It's not crucial, but I was curious, so I did a quick test and you're right! `x is ValueType` takes about a third as long.
StriplingWarrior