Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic type parameter and Nullable method overload

Hi
I have this code using generic and nullable:

// The first one is for class
public static TResult With<TInput, TResult>(this TInput o, 
          Func<TInput, TResult> evaluator)
    where TResult : class
    where TInput : class

// The second one is for struct (Nullable)
public static TResult With<TInput, TResult>(this Nullable<TInput> o, 
          Func<TInput, TResult> evaluator)
    where TResult : class
    where TInput : struct

Please note the TInput constraint, one is class, the other one is struct. Then I use them in:

string s;
int? i;

// ...

s.With(o => "");
i.With(o => ""); // Ambiguos method

It cause an Ambiguos error. But I also have the another pair:

public static TResult Return<TInput, TResult>(this TInput o,
          Func<TInput, TResult> evaluator, TResult failureValue)
    where TInput : class

public static TResult Return<TInput, TResult>(this Nullable<TInput> o,
          Func<TInput, TResult> evaluator, TResult failureValue)
    where TInput : struct

This one compiles successfully

string s;
int? i;

// ...

s.Return(o => 1, 0);
i.Return(o => i + 1, 0);

I got no clues why this happen. The first one seems Ok, but compiles error. The second one ('Return') should be error if the first one is, but compiles successfully. Did I miss something?

like image 713
Hendry Ten Avatar asked Apr 28 '11 06:04

Hendry Ten


People also ask

Can generic methods be overloaded?

A generic method can also be overloaded by nongeneric methods. When the compiler encounters a method call, it searches for the method declaration that best matches the method name and the argument types specified in the call—an error occurs if two or more overloaded methods both could be considered best ...

Which keyword is used to apply constraints on type parameter?

So here is the list of some of the constraints that you can add to the generic classes, using the where keyword: Restrict the generic class to use the type parameter of value or reference type only (as we discussed above). Restrict the type parameter T, to be implementing the specified interface.

What are generic constraints in c#?

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

Constraints within the generic method are not considered while choosing an overload - they're checked after the overload has been chosen.

Constraints within the types of the parameters are checked as part of choosing an overload. It's a bit confusing, but it makes sense eventually.

I have a blog post on this which may help to understand it further.

Additionally note that your second example has the additional argument which contributes to type inference, which is what makes the difference between the two. TResult is inferred to be int, which prevents the first overload from being valid - there's no conversion from (int? x) => x + 1 to Func<int?, int> whereas there is a conversion from (int x) => x + 1 to Func<int, int>.

like image 188
Jon Skeet Avatar answered Sep 26 '22 00:09

Jon Skeet