Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method overloading in generic class

I am working with a code that contains following overloaded method in generic class:

public class A<T>
{
    public void Process(T item) { /*impl*/ }
    public void Process(string item) { /*impl*/ }
}

When parametrizing the class for string do I lose the possibility to call the version with generic parameter?

var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
like image 612
nan Avatar asked May 30 '12 20:05

nan


People also ask

Can we overload a generic method in C#?

Answer: Yes, we can overload a generic methods in C# as we overload a normal method in a class. Q- If we overload generic method in C# with specific data type which one would get called? Answer: Function with specific data type i.e int will be called.

Can we overload action method in MVC?

A method used as a controller action cannot be overloaded..

Can we overload a method in subclass?

Note: In a subclass, you can overload the methods inherited from the superclass. Such overloaded methods neither hide nor override the superclass instance methods—they are new methods, unique to the subclass.

Can overloading be done with different return types?

Method overloading cannot be done by changing the return type of methods. The most important rule of method overloading is that two overloaded methods must have different parameters.


3 Answers

Specific types take precedence over generic types.

For example, this is what I tested with in LINQPad.

void Main()
{
    new A<string>().Process("Hello");
}

public class A<T>
{
    public void Process(T item) { Console.WriteLine("T"); }
    public void Process(string item) { Console.WriteLine("string"); }
}

// Output: string

If you have a problem with hiding the generic method, then you need to rethink something. By overloading a generic method with specific types, you are effectively saying, "Use the generic overload if you need to, but if you can, use the specific version, because it should know what is best."

like image 163
Kendall Frey Avatar answered Oct 22 '22 00:10

Kendall Frey


There is one way I just discovered, but it's a bit cross-eyed. Because generics and overloading get resolved in build time, you can define a generic method:

public static CallerClass
{
    public static CallGenericOverload<T>(GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val); 
    }   

    //We can also make an extension method. 
    //We don't have to of course, it's just more comfortable this way.
    public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val);
    }

}

public GenericClass<T>
{
     public string ProblemOverload(T val)
     {
         return "ProblemOverload(T val)";
     }
     public string ProblemOverload(string val)
     {
         return "ProblemOverload(string val)";
     }
}

Now, if we do the following:

var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)

You can use a similar trick if you define a generic class instead of a generic method. The important thing is that the parameter you transfer to ProblemOverload needs to be of type T rather than type string in the invocation. After all, the method CallGenericOverload knows it's getting a T at build time, so it's going to bind to the overload that accepts the parameter. It doesn't matter that it's actually going to get a string at runtime.

like image 24
GregRos Avatar answered Oct 21 '22 22:10

GregRos


Yes. This is documented in the C# spec, section 7.5.3, overload resolution.

From 7.5.3.6:

"While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In such cases, the tie-breaking rules of overload resolution above will pick the most specific member."

The example given in there states that in the case below, overload resolution for G<int>.F1 will pick non-generic

class G1<U>
{
    int F1(U u);
    int F1(int i);
}

The tie-breaking rule that applies here is outlined in 7.5.3.2, "Better function member":

In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.

  • If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
like image 5
jeroenh Avatar answered Oct 21 '22 22:10

jeroenh