简体   繁体   English

为什么选择泛型函数成员而不是非泛型函数?

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

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". 删除, EnumTest t = EnumTest.EnumEntry使其打印为“正常”。

And yet the standard appears to be pretty clear, from 14.4.2.2 Better function member the first discriminator to be applied is: 然而标准似乎很清楚,从14.4.2.2更好的功能成员应用的第一个鉴别器是:

  • If one of MP and MQ is non-generic, but the other is generic, then the non-generic is better. 如果MP和MQ中的一个是非泛型的,但另一个是通用的,那么非泛型更好。

Am I missing something or compiler bug? 我错过了什么或编译错误?

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: C#4.0规范 ,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: MSDN ,标题为“重载分辨率”,最后一个要点:

    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": C#语言规范 ,章节“7.5.3.2更好的功能成员”:

    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 { E 1 , E 2 , ..., E N } and two applicable function members MP and MQ with parameter types { P 1 , P 2 , ..., P N } and { Q 1 , Q 2 , ..., Q N } [...] 给定一个参数列表A,其中包含一组参数表达式{E 1 ,E 2 ,...,E N }和两个适用的函数成员MP和MQ,参数类型为{P 1 ,P 2 ,...,P N }和{Q 1 ,Q 2 ,...,Q N } [...]

    At this point the method with the optional parameter is already out of the game. 此时,带有可选参数的方法已经不在游戏中。 N is 1, but that method has two parameters. N是1,但该方法有两个参数。

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. 换句话说,没有任何可选参数的方法将是首选。

With default values for method parameters the overload resolution got extended. 使用方法参数的默认值,可以扩展重载决策。

Conceptually the method overload resolution from pre v4 will be run. 从概念上讲,将运行v4之前的方法重载分辨率。 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. 如果两个方法可用但是一个接受IFoo参数而另一个接受Foo(实现IFoo),则默认参数的方法不如参数计数与参数计数匹配的方法(数字是完全匹配)的特定方法在将Foo对象作为参数传递时将选择后者,因为它是完全匹配的。 more specific 更加具体

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM