更新 class 属性 inside Enumerable.Zip linq c#

Update class property inside Enumerable.Zip linq c#

我想从外部列表更新 IEnumerable 中的每个 class 属性。

class MyClass
{
    public int Value { get; set; }            
}

我尝试了以下方法

var numbers = new List<int>() { 1, 2, 3 };
var myclasses = Enumerable.Repeat(new MyClass(), numbers.Count);  

myclasses.Zip(numbers, (a, b) => a.Value = b).ToList();           // Set each property [Not working as expected]
myclasses.ToList().ForEach(x => Console.WriteLine(x.Value));      // Print all properties

我希望前面的代码将 Value 属性 in myclasses 分别设置为 1,2,3。但是此代码在每个 属性 中设置 3 并打印:

OUTPUT:
3
3
3

我不明白这种行为。有人可以向我解释为什么会这样,以及使用 LINQ 执行此操作的正确方法是什么。

Enumerable.Repeat(a, b) 生成一个包含 ba 的序列。所以你得到一个包含三倍 same 实例的序列(你只实例化 one new MyClass())。

因此,在最后一次执行 a.Value = b 时,您将单个 MyClass 实例的 Value 属性 设置为 3,而 x 在你的 WriteLine 中总是 相同的实例,包含 Value = 3.

创建 myclasses 的更好方法是

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass());

注意创建带有副作用的序列是。您实际上并没有使用由 Zip 编辑的序列 return,而是使用此 query 只是因为它在您的 lambda 中有副作用。

我想在您的实际应用程序中,myclasses 的创建和通过 Zip 的更新比您的问题更加分离。但如果没有,您可以将其全部简化为:

var myclasses = numbers.Select(i => new MyClass { Value = i });

更新

你现在只得到 0s 作为输出的原因是 延迟执行(再次:使用像 linq 这样的函数式编程方法只是为了它的副作用是棘手的).

直接的解决方法是在创建中添加ToList

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass()).ToList();

没有它,classes 仅在这一行被实例化:

myclasses.Zip(numbers, (a, b) => a.Value = b).ToList(); 

并且创建的 classes 被 returned 为一个序列 然后由 [=34 将其转换为 List =].但是你不使用那个 return 值。

所以在下一行

myclasses.ToList().ForEach(x => Console.WriteLine(x.Value));

您创建 个 class 的新实例

myclasses 如您所定义,它只是一个 查询 ,而不是该查询的 answer

所以我的最终建议是:

var myclasses = Enumerable.Range(1, numbers.Count).Select(i => new MyClass());
var updatedClasses = myclasses.Zip(numbers, (a, b) => {a.Value = b; return a;}).ToList(); 
updatedClasses.ForEach(x => Console.WriteLine(x.Value));

注意 我将 Zip 中的 lambda 更改为 return class 的实例而不是 int .