如何将List<List<Int32>>的初始化简化为IEnumerable<IEnumerable<Int32>>?

How to simplify the initialization of List<List<Int32>> as IEnumerable<IEnumerable<Int32>>?

我正在进行以下集合初始化:

Int32[,] v1 = new Int32[2, 2] { { 1, 2 }, { 3, 4 } };

IEnumerable<IEnumerable<Int32>> v2 = new List<List<Int32>> { { 2, 3 }, { 3, 4 } };

在第二行我得到错误:

No overload for method 'Add' takes 2 arguments

有没有办法使用最新的 C# 版本创建一个 IEnumerable<IEnumerable<Int32>> 而无需为主集合中的每个项目添加 new List<Int32>

IEnumerable<IEnumerable<Int32>> v2 = new List<List<Int32>> { 
  new List<Int32> { 2, 3 }, 
  new List<Int32> { 3, 4 } 
};

来自Object and Collection Initializers article in the C# Programming Guide

Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method.

所以,这里的问题是 List<T>.Add() 没有适当的重载需要可变数量的参数。

如果您定义自定义集合类型,您可以添加一个采用 params 参数的 Add() 方法:

class NestedList<T> : IEnumerable<IEnumerable<T>>
{
    List<List<T>> _list;

    public NestedList()
    {
        _list = new List<List<T>>();
    }

    public void Add(params T[] innerItems)
    {
        _list.Add(new List<T>(innerItems));
    }

    public IEnumerator<IEnumerable<TI>> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

现在我们有了一个接受可变数量参数的 Add() 方法,您可以使用嵌套的初始值设定项:

IEnumerable<IEnumerable<int>> v2 = new NestedList<int> { { 1, 2 }, { 3, 4 } };

无需围绕 List<List<T>> 编写包装器!

集合初始值设定项只是调用对象声明的名为 Add 的方法的语法糖,而 List<T> 不声明采用 2 个参数(或任何参数)的 Add 方法以上参数个数 1).

但是,一个集合初始化器也会调用一个名为Add的扩展方法。这意味着我们可以这样写:

public static class ListExtensions
{
     public static void Add<T>(this List<List<T>> list, params T[] items)
     {
         list.Add(new List<T>(items));
     }
}

然后我们可以这样写:

IEnumerable<IEnumerable<int>> collection = new List<List<int>>()
{
    { 1, 2 },
    { 3, 4 },
};

See it working here.


值得注意的是,这种 Add 方法只能作为扩展方法添加 -- List<T> 不可能自己声明它。这样做的原因是只有当列表包含其他列表时才有意义,并且无法定义仅适用于某些类型列表的实例方法。但是,您可以在扩展方法上添加各种类似的限制。你可以在 List<T> 上写一个扩展方法,它只适用于 T 是一个 class,或者实际上只有当 T 是另一个列表时才适用!