You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用LINQ正确初始化C#中的List<List<T>>?问题排查与优化

LINQ创建嵌套List<List>的问题解答

问题背景

近期编写C#代码时,尝试用LINQ创建List<List<Bar>>类型的嵌套列表(Bar为自定义struct),运行后所有行内容完全相同,不符合预期。推测原因是外层Enumerable.Repeat重复的是同一个List<T>的引用(List<T>是引用类型),而内层Repeat因Bar是值类型可生成独立实例。现咨询两个问题:

  1. 上述问题解释是否正确?
  2. 如何不使用显式嵌套循环,初始化具有独立行的List<List<T>>?

原代码示例:

namespace Foo
{
    public struct Bar
    {
        public float val;

        public Bar(float val) {  this.val = val; }  
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            int rows = 3;
            int cols = 4;

            List<List<Bar>> mat = Enumerable.Repeat(
                   Enumerable.Repeat(default(Bar), cols).ToList(),
                   rows
               ).ToList();
            
            foreach(var i in Enumerable.Range(0, rows * cols))
            {
                int row = i / cols;
                int col = i % cols;
                mat[row][col] = new Bar((float)i);
            }

            foreach (var row in Enumerable.Range(0, rows))
            {
                foreach (var col in Enumerable.Range(0, cols))
                {
                    Console.Write(mat[row][col].val + " ");
                }
                Console.Write("\n");
            }
        }
    }
}

原输出结果:

8 9 10 11
8 9 10 11
8 9 10 11

问题解答

1. 问题解释是否正确?

完全正确。

  • Enumerable.Repeat的行为是:对于值类型,会重复生成独立的实例;对于引用类型,只会重复返回同一个对象的引用。
  • 外层Repeat传入的是Enumerable.Repeat(default(Bar), cols).ToList()的结果——一个List<Bar>实例(引用类型),所以rows次重复返回的都是这个列表的引用,所有行指向的是同一个底层列表。
  • 内层Repeat处理的是值类型Bar,每次都会生成新的Bar实例,所以内层列表的元素是独立的,但由于所有行共享同一个内层列表实例,最后一次赋值(i=8到11)会覆盖之前的内容,导致所有行显示相同结果。

2. 不使用显式嵌套循环初始化独立行的方法

用Enumerable.Range配合Select替代外层的Enumerable.Repeat,让每一行都通过lambda表达式创建新的List<Bar>实例:

List<List<Bar>> mat = Enumerable.Range(0, rows)
    .Select(_ => Enumerable.Repeat(default(Bar), cols).ToList())
    .ToList();

修改后的代码运行后,输出结果符合预期:

0 1 2 3 
4 5 6 7 
8 9 10 11 

原理是:Enumerable.Range(0, rows)生成0到rows-1的序列,Select中的每个lambda表达式都会执行一次Enumerable.Repeat(...)并调用ToList(),每次都会创建全新的List<Bar>实例,因此所有行都是独立的。


内容的提问来源于stack exchange,提问作者jwezorek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:57:18