Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison of a generic type with its default value, without a generic class constraint, gives a compile time error

I just ran into this situation and i thought it was a nice opportunity to use the default keyword. But it doesn't compile and i can't think of why. The example below illustrates my problem:

public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result != default(TDataSource);
    }
}

You'll get an error on line 8 ("Operator '==' cannot be applied to operands of type 'TDataSource' and 'TDataSource'."). I thought using the default keyword would eliminate any comparison problems between reference types and value types.

Adding a generic constraint limiting TDataSource to reference types makes this piece of code compile.

Can somebody explain why the compiler won't fix this for me? Is it just not smart enough to see this would work?

This is related: Can't operator == be applied to generic types in C#?

[Edit] SLaks answer gave me some inspiration, the '==' operator won't work, but the Equals function should.

    public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result.Equals(default(TDataSource));
    }
}

This compiles would this function correctly?

like image 452
JJoos Avatar asked Sep 03 '10 13:09

JJoos


People also ask

Which of the following generic constraints restricts the generic type parameter to an object of the class?

Value type constraint If we declare the generic class using the following code then we will get a compile-time error if we try to substitute a reference type for the type parameter.

What does the generic constraint of type interface do?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

What is the purpose of the class constraint on a type parameter?

Object, you'll apply constraints to the type parameter. For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments. Once the compiler has this guarantee, it can allow methods of that type to be called in the generic class.

What are generic type constraints?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.


1 Answers

You cannot assume that every value type overrides the == operator. (And even if they did, there would be no way to call it using generics; it's a static method)

Instead, you should write

    return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
          || result.Equals(default(TDataSource)));

If result is null (and a reference type), the ReferenceEquals call will return true, so Equals won't be called and won't throw a NullReferenceException.
If TDataSource is a value type, the ReferenceEquals will compare two different boxed references (which may happen to contain the same value, but will still be different), so it will pass on to the Equals call.

like image 177
SLaks Avatar answered Nov 08 '22 23:11

SLaks