Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a generic function member chosen over a non-generic one?

Tags:

c#

.net

public enum EnumTest
{
    EnumEntry
}

public class TestClass
{
    public string FunctionMember(string s, EnumTest t = EnumTest.EnumEntry)
    {
        return "Normal";
    }

    public string FunctionMember<T>(T t)
    {
        return "Generic";
    }
}

class Program
{
    static void Main(string[] args)
    {
        TestClass t = new TestClass();

        Console.WriteLine(t.FunctionMember("a"));
    }
}

This prints "Generic". Removing , EnumTest t = EnumTest.EnumEntry makes it print "Normal".

And yet the standard appears to be pretty clear, from 14.4.2.2 Better function member the first discriminator to be applied is:

  • If one of MP and MQ is non-generic, but the other is generic, then the non-generic is better.

Am I missing something or compiler bug?

like image 487
Thomas Bonini Avatar asked Feb 15 '13 13:02

Thomas Bonini


People also ask

Can a generic method can be a member of an ordinary non generic class?

Yes, There are two level where you can apply generic type . You can apply generic type on Method level as well as Class level (both are optional). As above example you applied generic type at method level so, you must apply generic on method return type and method name as well. You need to change a bit of code.

What is generics in c# msdn?

Generic is a class which allows the user to define classes and methods with the placeholder. Generics were added to version 2.0 of the C# language. The basic idea behind using Generic is to allow type (Integer, String, … etc and user-defined types) to be a parameter to methods, classes, and interfaces.

What is generic in dotnet?

Generics are classes, structures, interfaces, and methods that have placeholders (type parameters) for one or more of the types that they store or use.


3 Answers

You are missing something. And that is the following:

You call the method with one parameter. There is only one method that has one parameter, the generic one. So that's the one that's chosen.

Only if it didn't find a matching method it would look at other methods with optional parameters.

References:

  1. C# 4.0 Specification, last paragraph in 21.4:

    As a tie breaker rule, a function member for which all arguments where explicitly given is better than one for which default values were supplied in lieu of explicit arguments.

  2. MSDN, heading "Overload resolution", last bullet point:

    If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.

  3. The C# Language Specification, Chapter "7.5.3.2 Better function member":

    Parameter lists for each of the candidate function members are constructed in the following way:

    • The expanded form is used if the function member was applicable only in the expanded form.
    • Optional parameters with no corresponding arguments are removed from the parameter list

    It continues like this:

    Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN } [...]

    At this point the method with the optional parameter is already out of the game. N is 1, but that method has two parameters.

like image 167
Daniel Hilgarth Avatar answered Nov 15 '22 21:11

Daniel Hilgarth


The docs say:

If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.

In other words, the method without any optional arguments will be preferred.

like image 30
O. R. Mapper Avatar answered Nov 15 '22 20:11

O. R. Mapper


With default values for method parameters the overload resolution got extended.

Conceptually the method overload resolution from pre v4 will be run. If that finds a match that match will be used. (Conceptually because this is not a description of how it works but how you can think of it)

In your case it finds exactly one match being your generic method

If it does not find a match it will look for methods that has a partial match and where the match can be completed with default values. In your case your none generice method would be found in this run however the resolution never comes this far due to already having found a match.

When removing the second paramter you end up in a situation where there's a generic and a non generic match. And the rule you qoute kicks in picking the non-generic.

All in all a good rule of thumb is that the most specific available method will be chosen.

A non-generic method that matches is more specific than a generic because the type can't vary. A method with default parameters is less specific than one where the argument count matches the parameter count (the numbers are an exact match) if two methods are available but one takes an argument of IFoo and the other takes a Foo (implemeting IFoo) then the latter will be chosen when passing a Foo object as argument because it's an exact match Ie. more specific

like image 39
Rune FS Avatar answered Nov 15 '22 19:11

Rune FS