为什么我要复制这个?当在结构体中使用LINQ时(如果我这样做是可以的)

本文关键字:如果 这样做 LINQ 复制 我要 结构体 为什么 | 更新日期: 2023-09-27 18:05:51

下面的代码在一个不可变结构体中包含一个简单的LINQ查询。

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之外的一个局部变量表达式或查询表达式,并使用本地代替。

有人知道为什么这是不允许的吗?

消息建议的修复工作正常:

    public IEnumerable<FlatRhombPoint> GetEdges()
    {
        var thisCopy = this;
        return from neighborIndex in NeighborIndexes;
             select thisCopy.GetEdge(neighborIndex);
    }

但这是标准做法吗?在结构体中没有这样的查询是否有原因?(在更大的计划中,制作副本并不会让我担心性能方面的问题)。

为什么我要复制这个?当在结构体中使用LINQ时(如果我这样做是可以的)

结构体上的实例方法是通过引用 this & &;隐藏的ref参数。
这就是为什么结构方法能够改变调用它们的结构的原因。

当你在lambda表达式或LINQ查询中使用this(或任何其他局部变量/参数)时,编译器会将其转换为编译器生成的闭包类的字段。

CLR不支持ref字段,因此捕获的this不可能像常规的this一样工作。(这也是不能在lambdas中使用ref参数的原因)

迭代器方法也有同样的问题& & &;它们被编译成一个隐藏的枚举器类,所有变量或参数都成为类中的字段(这就是迭代器不能接受ref形参的原因)。
然而,对于迭代器,c#做出了相反的决定。在迭代器内部,可以使用this,但它将被复制到枚举器类的一个字段中。
这意味着如果你在迭代器中改变了一个结构体,这种改变不会发生在调用者的副本上。

相关文章: