C# 重载方法是如何工作的

C# 重载方法是如何工作的,c#,.net,C#,.net,我已经编程了5年,第一次是Delphi,现在是c,所以我想我知道重载方法是如何工作的,但显然不知道 首先是一些代码 public enum TestEnum { Option1, Option2, Option3 } public class Setting { public Setting() { AddSettings(); } protected void CreateSetting<TEnum>(string AName,

我已经编程了5年,第一次是Delphi,现在是c,所以我想我知道重载方法是如何工作的,但显然不知道

首先是一些代码

public enum TestEnum { Option1, Option2, Option3 }

public class Setting
{
    public Setting()
    {
        AddSettings();
    }

    protected void CreateSetting<TEnum>(string AName, TEnum AValue) where TEnum : struct, IComparable, IFormattable
    {
        //do stuff
    }

    protected void CreateSetting(string AName, string AValue)
    {
        //do stuff
    }

    protected void CreateSetting(string AName, int AValue)
    {
        CreateSetting(AName, AValue.ToString());
    }

    protected void AddSettings()
    {
        CreateSetting("Language", (byte)0); //#1
        CreateSetting("BFL", "true"); //#2
        CreateSetting<TestEnum>("TestEnum", TestEnum.Option1); //#3
        CreateSetting("TestEnum", TestEnum.Option1); //#4
    }
}
public enum TestEnum{Option1,Option2,Option3}
公共班级设置
{
公共环境()
{
添加设置();
}
受保护的void CreateSetting(字符串AName,TEnum AValue),其中TEnum:struct、IComparable、IFormattable
{
//做事
}
受保护的void CreateSetting(字符串AName、字符串AValue)
{
//做事
}
受保护的void CreateSetting(字符串AName,int-AValue)
{
CreateSetting(AName,AValue.ToString());
}
受保护的void AddSettings()
{
CreateSetting(“语言”(字节)0);//#1
CreateSetting(“BFL”、“true”);/#2
CreateSetting(“TestEnum”,TestEnum.Option1);/#3
CreateSetting(“TestEnum”,TestEnum.Option1);/#4
}
}
为了便于解释,我在每次调用CreateSettings时都添加了一个号码

我的问题是:

Call#1调用了错误(通用)版本的CreateSettings,因为我对
字节进行了转换,但为什么

呼叫#2工作正常

呼叫#3也可以正常工作。我直接称之为gerneric版本

Call#4也可以工作,但通过一些“魔法”,编译器解析正确的(genneric)版本并调用它。但是为什么它会起作用呢


我发现#1调用错误的版本的原因与#4工作的原因相同。我只是想知道是否有人能给我一个解释

重载按预期工作,您声明:

#1调用了错误的版本

它调用正确的版本,因为您所做的是将
int
强制转换为
字节
,因此不再有
int
变量,而是有
字节
。您是否希望它与
int
重载匹配?怎么可能呢,您刚刚将变量转换为
字节

呼叫#4也能工作,但有一些“魔力”


这不是魔术,这基本上是因为与上面相同的原因而起作用的,类型既不是
int
也不是
string
,因此它可以调用的唯一其他可能的重载是泛型重载,因为“泛型”方法本质上表示任何其他类(这里的类型是
TestEnum
)调用的方法由重载解析过程确定

编译器构建一个可能的候选方法列表,这些候选方法可以根据传递的参数类型进行调用,然后根据一组规则对它们进行排序,这些规则根据可能发生的任何类型转换的质量确定哪个方法是调用的最佳选项。您可以在此处查看这些规则:

一般过载解决过程如下所述:

通过遵循这些规则并与您的每个场景进行比较,您应该能够看到在每种情况下您所遵循的规则。

Call#1

您在TEnum:struct、IComparable和IFormattable中创建了一个约束

这意味着类型TEnum要么是值类型,要么是实现两个接口的类型 您有一个byte参数,这意味着将调用的方法是方法1,因为byte是值类型,其他方法都不接受byte作为参数

呼叫2呼叫3

工作如期进行

呼叫4


同样,编译器将解析为第一个方法,因为Enum是一个值类型,而其他方法都不接受Enum类型作为参数,因此最合适的重载是方法1

,具体是使用哪个版本的.Net framework/Visual studio?调用#1在进行转换时调用泛型重载在enum和byteok之间,我所说的“wong”的意思是不同于我预期的。是的,我希望它会达到int版本,因为我不知道#4是一个有效的语法。我是在#1调用“错误”版本时想到这个的。@VMAtm它调用泛型重载,因为它既不是
字符串
,也不是
int
@JensBorrisholt别担心,这是一个有效的问题:)。如果您尝试向函数发送一个十进制值,您会看到它也会转到泛型值,只是为了让它更清楚:)@JensBorrisholt#4正在使用类型推断,即它允许您省略类型,并且编译器仍然可以解出您的意思,因为您的参数类型。如果存在任何歧义(例如,如果它可以匹配多个重载),您仍然会得到一个编译器错误。更多信息:您对调用#1的解释不正确,因为约束不是签名的一部分。请参见:。Call#1调用泛型方法,因为它是剩下的唯一候选方法(byte不是int或string)。这就是我的意思,它看到了所有的可能性,并且由于byte是一种值类型,它将与第一个方法一起使用,如果它是class而不是struct,它将给您一个编译时错误