C# List嵌套Tuple实例化与声明的语法差异问题
开发目标
创建元素为仅包含double类型值的二元组的List集合,目标结构示例如下:{ {1.0,1.1}, {1.2,1.3}, {1.4,1.5}, {...}, {...} }
其中{1.0,1.1}对应List[0],{1.2,1.3}对应List[1],{1.4,1.5}对应List[2],以此类推。
测试代码
Tuple<double,double> a1 = new Tuple<double,double>(1.0, 1.1); Tuple<double,double> a2 = new Tuple<double,double>(1.2, 1.3); Tuple<double,double> a3 = new Tuple<double,double>(1.4, 1.5); // 编译报错写法 //List< Tuple<double,double> > a4 = new List< Tuple<double, double> >(a1, a2, a3); //ERROR //List< Tuple<double,double> > a7 = new List< Tuple<double, double> >{a1, a2, a3}(); //ERROR // 正常编译写法 List< Tuple<double,double> > a5 = new List< Tuple<double, double> >{a1, a2, a3}; //COMPILES List< Tuple<double,double> > a6 = new List< Tuple<double, double> >(){a1, a2, a3}; //COMPILES
技术疑问
- 上述代码中a4、a5、a6、a7四种写法,为什么实例化时的圆括号
()可以省略,但花括号{}不能省略? - a4的写法中,圆括号
()本身用于传入构造函数的实例化参数,为什么不能通过()传入a1、a2、a3三个Tuple对象完成List<>的实例化? - a4写法的报错原因,和a7写法的报错原因是否一致?
补充说明:已知方括号
[]是数组/集合的元素索引访问语法,因此未尝试相关写法;另外了解ValueTuple类型,但出于兼容旧版本C#与.NET版本的需求选择使用Tuple类型,无需推荐ValueTuple替代方案。
问题解答
关于括号的省略规则:
C#中调用无参构造函数时,若后续紧跟对象/集合初始化器,允许省略无参构造的空圆括号(),因此new List<Tuple<double,double>>{a1,a2,a3}和new List<Tuple<double,double>>(){a1,a2,a3}是完全等价的语法,编译器会自动补全无参构造的调用逻辑。
而此处的花括号{}是集合初始化器的法定边界符,不属于构造函数语法的一部分:只有写了这对花括号,编译器才会判定你要在实例化集合的同时,将花括号内的元素依次通过Add方法添加到集合中;如果省略花括号,编译器只会按普通构造函数传参的逻辑解析代码,不会自动执行集合元素初始化的操作,因此花括号不能省略。a4写法无法通过构造函数传参初始化的原因:
List<T>不存在接收3个T类型独立参数的构造函数,其公开的构造函数仅有3个重载:
- 无参构造:创建默认初始容量的空列表
List<T>(int capacity):创建指定初始容量的空列表List<T>(IEnumerable<T> collection):将传入的可枚举集合中的元素复制到新列表中
a4中直接传入3个独立的Tuple<double,double>对象,既不匹配容量参数的int类型要求,也不匹配可枚举集合的参数要求,没有对应的构造函数重载,因此编译失败。如果要通过构造函数传参实现相同效果,需要先将3个元组包装为可枚举类型(例如数组),写法为new List<Tuple<double,double>>(new[]{a1,a2,a3}),此时会匹配第三个构造函数重载。
- a4与a7的报错原因完全不同:
- a4属于构造函数重载匹配失败:语法书写顺序符合
new 类型(构造参数)的规则,但传入的参数类型、数量没有匹配的构造函数签名。 - a7属于语法结构非法:C#对象创建表达式的固定顺序为
new 类型名 [构造函数调用] [初始化器],构造函数的圆括号必须写在初始化器花括号之前,a7将初始化器放在了构造函数括号前面,违反了基础语法规则,编译器无法将其解析为合法的对象创建语句。
内容的提问来源于stack exchange,提问作者Stev
相关产品推荐
相关产品推荐

