最近我写了一些类似于下面的代码
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
型
我认为问题在于LINQ表达式。内部LINQ表达式是正确的,因为Bar
是struct
,它在重复struct
时使用值语义,但外部LINQ表达式将重复引用同一个List<T>
,因为List<T>
是一个类,因此使用引用语义。
我的问题是(1)上面对这个问题的解释正确吗?(2)在不使用显式嵌套循环的情况下初始化List<List<T>>
的更好方法是什么?
1条答案
按热度按时间toe950271#
外部列表的内部列表包含相同的
val
值的原因是Enumerable.Repeat<List<Bar>>(List<Bar>, Int32)
的第一个参数只计算一次,所以它们实际上是相同的列表重复rows
次。为了让自己相信这一点,你可以使用
object.ReferenceEquals()
来Assertmat
的所有项都是相等的:字符串
因此,
foreach(var i in Enumerable.Range(0, rows * cols))
循环会多次覆盖该列表的内容,最终迭代的内容将获胜。演示小提琴#1 here。
假设你想要不同的列表,包含以下内容:
型
您可以使用
Enumerable.Range(int start, int count)
的嵌套调用来简洁地创建不同列表的锯齿列表,如下所示:型
演示小提琴#2 here。