为什么在结构中使用LINQ时必须复制“this”(如果我这样做,那么它是否可以)?

时间:2013-03-25 16:03:32

标签: c# linq struct

下面的代码在不可变结构中包含一个简单的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);
    }

但这是标准做法吗?是否有理由在结构中没有这样的查询? (在制作副本的更大方案中,并不担心我的表现如此)。

1 个答案:

答案 0 :(得分:20)

结构的实例方法使用引用调用this - a hidden ref parameter
这就是结构方法能够改变它们被调用的结构的原因。

在lambda表达式或LINQ查询中使用this(或任何其他局部变量/参数)时,编译器会将其转换为compiler-generate closure class上的字段。

CLR不支持ref字段,因此捕获的this无法以与常规this相同的方式工作。 (这也是你不能在lambdas中使用ref参数的原因)

迭代器方法有同样的问题 - 它们被编译成一个隐藏的枚举器类,所有变量或参数都成为类中的字段(这就是迭代器不能接受ref参数的原因)。
但是,对于迭代器,C#做出了相反的决定。在迭代器中,您can use this,但它将被复制到枚举器类的字段中 这意味着如果你在迭代器中改变一个struct,那么突变就不会发生在调用者的副本中。