更新 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)
生成一个包含 b
次 a
的序列。所以你得到一个包含三倍 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 });
更新
你现在只得到 0
s 作为输出的原因是 延迟执行(再次:使用像 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
.
我想从外部列表更新 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)
生成一个包含 b
次 a
的序列。所以你得到一个包含三倍 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 });
更新
你现在只得到 0
s 作为输出的原因是 延迟执行(再次:使用像 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
.