Search code examples
c#genericsoverloadingfunction-call

the order of function calls in c# (overloaded methods)


Why is the second function called here first and not the first. And how does the choice of functions occur in such situations?

class Program {
  static void Main(string[] args) {
    var a = new A<char>();
    Use(a);
  }

  static void Use(IEnumerable<char> e) { 
    foreach (var _ in e) ;
    Console.WriteLine("Use(IEnumerable<char>)");
  }

  static void Use<T>(T e) where T : IEnumerable<char> { 
    foreach (var _ in e) ;
    Console.WriteLine("Use<T>(T) where T : IEnumerable<char>");
  }


  static void Use<T>(A<char> e) { 
    foreach (var _ in e) ;
    Console.WriteLine("Use<T>(A<char>)");
  }
}

class A<T> : IEnumerable<T> {
...
}

Solution

  • Basically, the C# compiler follows very complex rules for overloading. See section 12.6.4 of the C# v7 standard for the painstaking details.

    In this particular case, the compiler chooses the generic method instead of the non-generic method because it means the parameter is an exact match for the argument, which is deemed to be a "better conversion". It's a little bit like this:

    void M(object o) { ... }
    void M(string s) { ... }
    ...
    M("test"); // Calls M(string)
    

    The second method is a "better" function here because the conversion from string to string is "better" than the conversion from string to object.

    In your case, it's a conversion from A<char> to A<char>, vs a conversion from A<char> to IEnumerable<char>.

    As for why the second method is called rather than the third method - your third method is generic, but T can't be inferred via type inference, so it's not an applicable function member. If you change it to be a non-generic method (static void Use(A<char> e)), then that will be the best function member, because one of the tie-breaking rules is that a non-generic method is "better" than a generic method.