Boris B.
Boris B.

Reputation: 5024

Method overloading based on generic constraints?

Can I somehow have overloaded methods which differ only by generic type constraints?

This does not compile:

    void Foo<T>(T bar) where T : class
    {

    }

    void Foo<T>(T bar) where T : struct
    {

    }

Since these are "open" methods, the actual method should be closed/constructed/fully-defined when it's referenced elsewhere in code with a concretely-typed T, and then it would be clear which overload to call.

The obvious solution is not to overload them, but I'm wondering why this doesn't work in C#?

Additional question: If this is just a C# compiler constraint, does the IL allow such an overload?

Upvotes: 19

Views: 2512

Answers (5)

palapapa
palapapa

Reputation: 949

There are really strange corner cases that allow you to do this, which involve nullable generic parameters.

This will compile:

class Foo
{
    public void Bar<T>(T? t) where T : struct { }
    public void Bar<T>(T? t) where T : class { }
}

So will this:

class Foo
{
    public void Bar<T>(T? t) where T : struct { }
    public void Bar<T>(T t) where T : class { }
}

But not this:

class Foo
{
    public void Bar<T>(T t) where T : struct { }
    public void Bar<T>(T? t) where T : class { }
}

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500275

Can I somehow have overloaded methods which differ only by generic type constraints?

No. It's not part of the method signature in terms of overloading, just like the return type isn't.

There are horrible ways of "pseudo-overloading" in some cases, but I wouldn't recommend going down that path.

For more information, you might want to read:

Upvotes: 11

Dmitry Vodolazsky
Dmitry Vodolazsky

Reputation: 1

struct _Val_Trait<T> where T:struct { }
struct _Ref_Trait<T> where T:class { }

static void Foo<T>(T bar, _Ref_Trait<T> _ = default(_Ref_Trait<T>)) where T:class
{
    Console.WriteLine("ref");
}

static void Foo<T>(T bar, _Val_Trait<T> _ = default(_Val_Trait<T>)) where T:struct
{
    Console.WriteLine("val");
}

static void Main() 
{
    Foo(1);            // -->"val"
    Foo(DateTime.Now); // -->"val"
    Foo("");           // -->"ref"

    //but:
    //Foo(null); - error: type cannot be inferred
}

Upvotes: -1

Felipe Pessoto
Felipe Pessoto

Reputation: 6969

An update. In C# 7.3 generic constraints are now part of overload decision.

So, this code will compile:

class Animal { } 
class Mammal : Animal { } 
class Giraffe : Mammal { }
class Reptile : Animal { } 

static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main() 
{ 
    Foo(new Giraffe()); 
}

Upvotes: 0

Oded
Oded

Reputation: 498972

This is not possible.

Generic constraints are not considered to be part of the method signature for purposes of overloading.

If you want to allow both value types and reference types, why constrain at all?

Upvotes: 5

Related Questions