为什么我要复制“这个"?在结构中使用 LINQ 时(如果我这样做可以吗)? [英] Why do I have to copy "this" when using LINQ in a struct (and is it OK if I do)?
问题描述
下面的代码在不可变结构中包含一个简单的 LINQ 查询.
The code belows contains a simple LINQ query inside an immutable struct.
struct Point
{
static readonly List</*enum*/> NeighborIndexes;
//and other readonly fields!
public IEnumerable<FlatRhombPoint> GetEdges()
{
return from neighborIndex in NeighborIndexes;
select GetEdge(neighborIndex);
}
}
它不会编译.
里面的匿名方法、lambda 表达式和查询表达式结构无法访问this"的实例成员.考虑复制'this' 指向匿名方法 lambda 之外的局部变量表达式或查询表达式并使用本地代替.
Anonymous methods, lambda expressions, and query expressions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression or query expression and using the local instead.
有人知道为什么不允许这样做吗?
消息建议的修复工作正常:
The fix the message suggests works fine:
public IEnumerable<FlatRhombPoint> GetEdges()
{
var thisCopy = this;
return from neighborIndex in NeighborIndexes;
select thisCopy.GetEdge(neighborIndex);
}
但这是标准做法吗?是否有理由在结构中没有这样的查询?(从更大的角度来看,制作副本不会让我担心性能方面的问题).
But is this standard practice? Are there reasons for not having queries like this in structs? (In the bigger scheme of things making a copy does not worry me performance-wise as such).
推荐答案
结构体上的实例方法通过引用到this
–一个隐藏的ref
参数.
这就是为什么结构体方法能够改变它们被调用的结构体的原因.
Instance methods on structs are called with a reference to this
– a hidden ref
parameter.
This is why struct methods are able to mutate the structs they're called on.
当您在 lambda 表达式或 LINQ 查询中使用 this
(或任何其他局部变量/参数)时,编译器会将其转换为 编译器生成闭包类.
When you use this
(or any other local variable / parameter) inside a lambda expression or LINQ query, the compiler turns it into a field on a compiler-generate closure class.
CLR 不支持 ref
字段,因此捕获的 this
不可能与常规的 this
以相同的方式工作.(这也是你不能在 lambdas 中使用 ref
参数的原因)
The CLR does not support ref
fields, so it would be impossible for the captured this
to work the same way as a regular this
. (this is also the reason that you can't use ref
parameters inside lambdas)
迭代器方法也有同样的问题–它们被编译成一个隐藏的枚举器类,所有变量或参数都成为类中的字段(这就是迭代器不能接受ref
参数的原因).
但是,对于迭代器,C# 做出了相反的决定.在迭代器中,您可以使用this
,但它会被复制到枚举器类上的一个字段.
这意味着如果你在迭代器中改变一个结构体,改变不会发生在调用者的副本上.
Iterator methods have the same issue – they are compiled into a hidden enumerator class, and all variables or parameters become fields in the class (this is why iterators cannot take ref
parameters).
However, for iterators, C# made the opposite decision. Inside an iterator, you can use this
, but it will be copied to a field on the enumerator class.
This means that if you mutate a struct inside an iterator, the mutations will not happen to the caller's copy.
这篇关于为什么我要复制“这个"?在结构中使用 LINQ 时(如果我这样做可以吗)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!