C# 关键字';参数';工作

C# 关键字';参数';工作,c#,generics,compiler-construction,parameters,C#,Generics,Compiler Construction,Parameters,以下代码示例打印: T T[] T[] 虽然前两行和预期的一样,为什么编译器选择param数组作为常规数组 public class A { public void Print<T>(T t) { Console.WriteLine("T"); } public void Print<T>(params T[] t) { Console.WriteLine("T[]"); } } cla

以下代码示例打印:

T
T[]
T[]
虽然前两行和预期的一样,为什么编译器选择param数组作为常规数组

public class A
{
    public void Print<T>(T t)
    {
        Console.WriteLine("T");
    }

    public void Print<T>(params T[] t)
    {
        Console.WriteLine("T[]");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Print("string");
        a.Print("string","string");
        a.Print(new string[] {"a","b"});
    }
}
公共A类
{
公开作废打印(T)
{
控制台。写入线(“T”);
}
公共作废打印(参数T[]T)
{
Console.WriteLine(“T[]);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
A=新的A();
a、 打印(“字符串”);
a、 打印(“字符串”、“字符串”);
a、 打印(新字符串[]{“a”,“b”});
}
}
在发动机罩下

a.Print("string","string");
只是语法上的糖

a.Print(new string[]{"string","string"});

编辑:正如我所说的,
params
关键字只会自动为您创建数组,您告诉编译器:要么直接接受
T
数组,要么使用X输入参数来构造该数组。

params允许您传递相同类型的多个对象。这是一种传递数组的快捷方式

我认为这实际上更多地与类型推断有关,而不是与params关键字有关。推理机在第三行假定T的类型为string[],因此将其传递给第一个方法


尝试Console.WriteLine(typeof(T))如果您不相信我,当使用params关键字时,编译器将对正式函数声明以及实际函数调用进行一些翻译

正式功能声明:

在引擎盖下,IL将转换为与

public void Print<T>(T[] array);
成为与相同的IL代码

a.Print(new string[]{"string1", "string2"});
这就是为什么第2行和第3行的输出相同,因为在引擎盖下,它们被转换为完全相同的IL


关于第3行为什么不打印“T”的问题是因为.NET编译器总是试图找到最佳重载匹配,所以第2行和第3行都调用了T[]版本,而不是普通的T。

正如arul所说的那样。如果在reflector中打开项目,将看到以下内容:

a.Print<string>(new string[] { "string", "string" });
a.Print(新字符串[]{“字符串”,“字符串”});

除了其他人所说的之外,params关键字还导致生成的for array参数具有paramaryattribute。所以,这个

public void Print<T>(params T[] t) { }
而不是

a.Print(new string[] { "string", "string" });

不,你听不懂我说的。第一个推理机将T映射到类型字符串,第三个将T映射到类型字符串[]。只需将控制台输出替换为console.WriteLine(typeof(T));你会see@George,您不正确:T在所有三种情况下都是字符串。第二个和第三个方法调用与计算机相同。好吧,也许我完全误解了什么。你能详细解释一下你的答案吗?MSIL没有参数的params关键字的概念。所以C#编译器会看到参数上的参数,当被调用时,实际上会将参数更改为数组。啊,我明白了。您的示例一开始没有意义,因为您看到的是第二个方法调用,而不是最后一个方法调用。现在我明白了。谢谢我认为问题是编译器为什么不选择a。打印第一个方法,规则说params方法更适合。因为在调用实际的params方法时,可变长度参数集将转换为T[],因此它更适合T[]版本。请记住,数组是它自己的数组类,而对于第一个版本,string是一个类,而不是数组类。正如其他人所写的,没有params数组,也没有任何“到params数组的映射”。它只是一个数组,params关键字允许编写更简洁的语法
public void Print<T>([ParamArray] T[] t); { }
a.Print("string", "string");
a.Print(new string[] { "string", "string" });