Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Method Resolution, long vs int

class foo {   public void bar(int i) { ... };   public void bar(long i) { ... }; }   foo.bar(10); 

I would expect this code to give me some error, or at least an warning, but not so...

What version of bar() is called, and why?

like image 705
Vegar Avatar asked May 25 '11 13:05

Vegar


2 Answers

The int version of bar is being called, because 10 is an int literal and the compiler will look for the method which closest matches the input variable(s). To call the long version, you'll need to specify a long literal like so: foo.bar(10L);

Here is a post by Eric Lippert on much more complicated versions of method overloading. I'd try and explain it, but he does a much better job and I ever could: http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

from the C# 4.0 Specification:

Method overloading permits multiple methods in the same class to have the same name as long as they have unique signatures. When compiling an invocation of an overloaded method, the compiler uses overload resolution to determine the specific method to invoke. Overload resolution finds the one method that best matches the arguments or reports an error if no single best match can be found. The following example shows overload resolution in effect. The comment for each invocation in the Main method shows which method is actually invoked.

 class Test {          static void F() {         Console.WriteLine("F()");          }            static void F(object x) {         Console.WriteLine("F(object)");            }       static void F(int x) {         Console.WriteLine("F(int)");           }       static void F(double x) {         Console.WriteLine("F(double)");            }       static void F<T>(T x) {         Console.WriteLine("F<T>(T)");          }       static void F(double x, double y) {         Console.WriteLine("F(double,double)");         }             static void Main() {         F();                // Invokes F()         F(1);           // Invokes F(int)         F(1.0);         // Invokes F(double)         F("abc");       // Invokes F(object)         F((double)1);       // Invokes F(double)         F((object)1);       // Invokes F(object)         F<int>(1);      // Invokes F<T>(T)         F(1, 1);        // Invokes F(double, double)       }  } 

As shown by the example, a particular method can always be selected by explicitly casting the arguments to the exact parameter types and/or explicitly supplying type arguments.

like image 88
kemiller2002 Avatar answered Sep 25 '22 20:09

kemiller2002


As Kevin says, there's an overload resolution process in place. The basic sketch of the process is:

  • Identify all the accessible candidate methods, possibly using type inference on generic methods
  • Filter out the inapplicable methods; that is, the methods that cannot work because the arguments don't convert implicitly to the parameter types.
  • Once we have a set of applicable candidates, run more filters on them to determine the unique best one.

The filters are pretty complicated. For example, a method originally declared in a more derived type is always better than a method originally declared in a less derived type. A method where the argument types exactly match the parameter types is better than one where there are inexact matches. And so on. See the specification for the exact rules.

In your particular example the "betterness" algorithm is straightforward. The exact match of int to int is better than the inexact match of int to long.

like image 45
Eric Lippert Avatar answered Sep 25 '22 20:09

Eric Lippert