17

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

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

4

1 回答 1

21

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

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

CLR 不支持ref字段,因此捕获的内容不可能this与常规this. (这也是不能ref在 lambda 中使用参数的原因)

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

于 2013-03-25T16:05:51.967 回答