39
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?

Vegar
  • 12,828
  • 16
  • 85
  • 151

3 Answers3

54

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.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
kemiller2002
  • 113,795
  • 27
  • 197
  • 251
  • Fortunately that's a particularly bizarre and unrealistic example of an overload resolution problem (in the link you gave to my blog.) Hopefully hardly anyone actually runs into that in real life. – Eric Lippert May 25 '11 at 16:38
  • What I really like about the article is that is shows how something which looks like it would be simple on the surface can turn out to be something wickedly complex. Briefly looking at, overload resolution seems simple, but in reality the number of cases makes it extremely difficult to get right. – kemiller2002 May 25 '11 at 16:58
  • Indeed, overload resolution is at least of complexity class NP-HARD in C#. You can (in theory) make the compiler solve the Traveling Salesman problem to work out which overload to call! – Eric Lippert May 25 '11 at 17:01
  • Tanks! I read Erics article before I posted, but found it to complicated for my simple case... Guess I should go get a copy of the specs, though... – Vegar May 26 '11 at 07:43
12

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
4

I would say if you exceed below limit

-2,147,483,648 to 2,147,483,647

control will go to long

Range for long

–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Max value for int

foo.bar(-2147483648);

or

foo.bar(2147483648);

Long will get control if we exceed the value by 2147483648

Pankaj
  • 9,749
  • 32
  • 139
  • 283