代码之家  ›  专栏  ›  技术社区  ›  user764754

集合初始化器内的集合表达式与编译器

c#
  •  2
  • user764754  · 技术社区  · 8 月前

    在C#中,这个 collection expression 不与列表编译 collection initializer (在我看来,一切都应该到位,但Roslyn开发人员必须有他们的理由):

    var list = new List<int[]>
    {
        [ 1, 2 ] // Compiler error CS1501
    };
    list.Add([1, 2]); // Although semantically equivalent, this compiles
    

    我的问题是:为什么在将集合表达式包装在另一个表达式中(通过在其周围加括号)时,它突然起作用?因为,事实上,这可以编译:

    var list = new List<int[]>
    {
        ([ 1, 2 ]) // Works
    };
    

    为什么当集合表达式被放置在一个额外的表达式中时,编译器似乎变得更聪明了?这是某种魔术表演吗?可能不会,因为在这里集合表达式不会自动转换为 Array<int> :

    var arr = ([1, 2]); // Compiler error CS9176
    
    1 回复  |  直到 8 月前
        1
  •  2
  •   Ivan Petrov    8 月前

    这很可能是因为我们使用了对象初始化器语法和索引器 [] 是一种特殊的属性,如成员(我认为它是默认的属性,名为 Item )

    所以,当你正常写作时 list[0] = 3 ,就好像你在写 list.Item(0) = 3

    带有索引器的类的简短演示代码:

    public class Foo {
        private int[] arr = new int[100];
        
        public int Bar { get; set; }
        
        // public int Item(int i)
        public int this[int i]
        {
            get { return arr[i]; }
            set { arr[i] = value; }
        }
    }
    
    void Main() {
        var foo = new Foo {
            [0] = 42, // Item(0) = 42
            [1] = 43, // Item(1) = 43
            Bar = 3
        };
    }
    

    因此,当编译器遇到 [ 它在思考 项目 将被设置(查找属性/成员名称,如 Bar [x] )

    在你的情况下 List<int[]> ,添加括号时 ( 对于成员来说,这是一个无效字符,因为它发现,这实际上是新的集合语法。在此之前,它会尝试确保它得到一个有效的setter表达式 [0] = 3 .

    这很有趣,因为 List 这始终是编译时有效的语法,但保证会出现运行时错误(即使我们设置了容量):

    var baz = new List<int[]>(10) {
        [0] = [1,2,3],
        [1] = [4,5,6]
    };
    

    你能做的就是一直使用新语法:

    List<int[]> baz = [
        [1, 2, 3], 
        [4, 5, 6]
    ];
    

    var bar = (List<int[]>) [
        [1, 2, 3], 
        [4, 5, 6]
    ];