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);
}
}
It does not compile.
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.
Does any one know why this is not allowed?
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).
Skip, Take and other method of LINQ does not return any collection. They return IEnumerable interface that allows to get next element from underlying source.
LINQ to objects – Allows querying in-memory objects like arrays, lists, generic list and any type of collections. LINQ to XML – Allows querying the XML document by converting the document into XElement objects and then querying using the local execution engine.
Structs copy the entire value on the assignment, whereas reference types copy the reference on assignment. So, large reference type assignments are cheaper than the value types. Instance field declarations in Struct cannot include variable initializers. But, static fields in Struct can include variable initializers.
The struct (structure) is like a class in C# that is used to store data. However, unlike classes, a struct is a value type. Suppose we want to store the name and age of a person. We can create two variables: name and age and store value.
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.
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.
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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With