Last time, we saw that the this parameter to an instance method in a struct is passed by reference, allowing the method to re-assign this or pass it as a ref parameter.
Due to limitations in the CLR, the this parameter to an iterator method is not a reference to the caller’s struct, and is instead a copy of the value. Quoting the spec (§7.6.7)
- When this is used in a primary-expression within an instance method or instance accessor of a struct, it is classified as a variable. The type of the variable is the instance type (§10.3.1) of the struct within which the usage occurs.
- If the method or accessor is not an iterator (§10.14), the this variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a ref parameter of the struct type.
- If the method or accessor is an iterator, the this variable represents a copy of the struct for which the method or accessor was invoked, and behaves exactly the same as a value parameter of the struct type.
To explain why, you’ll need to understand how iterators are compiled. As Jon Skeet explains, an iterator method is compiled into a nested class that implements IEnumerable, with the original code transformed into a state machine. This nested class has fields to store the method’s parameters (which includes this for instance methods) so that the iterator code can use them.
This is why iterators cannot take ref parameters; the CLR cannot store a reference (as opposed to a reference type) in a field. Therefore, the this parameter is passed to iterator methods by value, not by reference.
This is also why anonymous methods in structs cannot use this; anonymous methods are also compiled to methods in separate classes and so cannot inherit the ref parameter.
This means that if you change the Mutate method from before into an iterator, the code will still compile (!), but the calling method will not see the changes.
static void Main() {
Mutable m = new Mutable();
m.MutateWrong().ToArray(); //Force the iterator to execute
Console.WriteLine("In Main(): " + m.Value);
}
struct Mutable {
public int Value;
public IEnumerable<int> MutateWrong() {
this = new Mutable();
MutateStruct(ref this);
Console.WriteLine("Inside MutateWrong(): " + Value);
yield break;
}
}
static void MutateStruct(ref Mutable m) {
m.Value++;
}
This code prints
Inside MutateWrong(): 1
In Main(): 0
In summary, don’t mutate structs in iterators (or
at all, if you can help it).
I don’t know why this isn’t a compiler error.
Other posts
-
A _read-only_ object is an object that does not expose any way to change it....
-
{% assign openTag = '{%' %} [Last time]({% post_url 2013-06-09-writing-about-jekyll-in-jekyll %}), we saw how to...
-
[Jekyll](http://jekyllrb.com) is a very nice system for writing blogs. However, it does have some shortcomings,...
-
The next step in [migrating my blog to Jekyll]({% post_url 2013-05-31-migrating-from-blogger-to-jekyll %}) was to convert...
-
The first step in my migration to Jekyll was to import my old posts into...
-
My new design is powered by Jekyll and LESS (the LESS does as much or...
-
After nearly a year of inactivity, I have finally returned to my blog. I had...
-
{% raw %} If you open an older ASP.Net MVC3 project in Visual Studio 2012,...
-
{% raw %} Last year, Microsoft announced a simple new feature in C# 5: Caller...
-
{% raw %} If you use the ASP.Net MVC 3 [Compare] validation attribute on a...
-
{% raw %} CSRF attacks are one of the many security issues that web developers...
-
{% raw %} What’s wrong with the following code? {% endraw %} {% highlight csharp...
-
{% raw %} One common misconception about web security is that protecting important actions with CAPTCHAs...
-
{% raw %} One of the most useful additions to the .Net 4.0 base class...
-
{% raw %} ASP.Net MVC uses the new (to ASP.Net 3.5) Http*Base wrapper classes (HttpContextBase,...
-
{% raw %} People sometimes wonder why C# 5 needs to add caller info attributes,...
-
{% raw %} UPDATE: Now that the Visual Studio 11 beta has shipped with this...
-
{% raw %} UPDATE: Now that the Visual Studio 11 beta has shipped with this...
-
{% raw %} UPDATE: Now that the Visual Studio 11 beta has shipped with this...
-
{% raw %} One common question about ASP.Net MVC is how to make “default” controller....
-
{% raw %} Update: This bug was fixed in XRegExp 1.5.1. However, as far as...
-
{% raw %} Part 1 is here Some languages have better ways to pass boolean...
-
{% raw %} Have you ever written code like this: {% endraw %} {% highlight...
-
{% raw %} C# is usually touted as a type-safe language. However, it is not...
-
{% raw %} Until now, I've been focusing on only one of the differences between...
-
{% raw %} When working with large .Net applications, it can be useful to find...
-
{% raw %} A .Net event actually consists of a pair of accessor methods named...
-
{% raw %} Sometimes, it can be useful to make an extension method specifically for...
-
{% raw %} Unlike WinForms or native Win32 development, WPF provides a rich layout model...
-
{% raw %} This is part 5 in a series about state and function pointers;...
-
{% raw %} This is part 4 in a series about state and function pointers;...
-
{% raw %} .Net supports two kinds of delegates: Open delegates and closed delegates. When...
-
{% raw %} This is part 3 in a series about state and function pointers;...
-
{% raw %} This is part 2 in a series about state and function pointers;...
-
{% raw %} Most languages – with the unfortunate exception of Java – allow functions...
-
{% raw %} Many people write ForEach extension methods for MVC WebForms views, which take...
-
{% raw %} Razor’s inline helpers allow you to create lambda expression that return markup...
-
{% raw %} In addition to normal and static helpers, Razor supports inline helpers, (also...
-
{% raw %} Razor helpers can be extremely useful, but they are designed to be...
-
{% raw %} The Boot Camp drivers in the latest generation of MacBook Pros now...
-
{% raw %} We’ll continue our trek into Razor’s class-level features with helpers. Helpers are...
-
{% raw %} After looking at how Razor’s Execute() method is generated, we will turn...
-
{% raw %} Last time, we saw how basic Razor constructs are translated into C#....
-
{% raw %} After looking at the various assemblies in the WebPages framework, we will...
-
{% raw %} Last time, we saw how standalone Razor pages are served. MVC3 maintains...
-
{% raw %} Last time, we saw that ASP.Net Web Pages are implemented in two...
-
{% raw %} Razor involves two distinct components: The Razor engine and the WebPages framework....
-
{% raw %} jQuery makes it very easy to modify a DOM tree. For example,...
-
{% raw %} Last time, we saw that there are severe limitations in creating ASPX...
-
{% raw %} ASP.Net pages can inherit from custom classes (as long as they inherit...
-
{% raw %} .Net developers frequently need to build connection strings, especially when connecting to...
-
One of the unique features of ASP.Net WebPages (formerly Razor) is automatic HTML encoding. All...
-
{% raw %} C# 4.0 adds support for optional parameters. The following code prints 4:...
-
{% raw %} The new ASP.Net WebPages view engine (formerly Razor) allows you to create...
-
{% raw %} .Net DataTables can be very useful when writing data-driven applications. However, they...
-
{% raw %} When designing fluent APIs, one issue that comes up is partial type...
-
{% raw %} A common chore in developing real-world C# applications is implementing value semantics...
-
This post
-
Usually, you cannot pass ref this as a parameter, since this is not a writable...
-
VB.Net’s Nothing keyword is is not the same as C#’s null. MSDN states, “Assigning Nothing...
-
jQuery contains a powerful and flexible animation engine. However, it has some limitations, primarily due...
-
A generic class can specify that its generic parameter must inherit a type. However, there...
-
In part 1, we discussed the simple approach to making a nested iterator. However, we...
-
C# 2.0 introduced a powerful feature called an iterator, a method which returns an IEnumerable<T>...
-
My previous post stretched the limit of simple copy prevention. Beyond this point, it gets...
-
The methods discussed in my previous post are crude and ugly. Most of the time,...
-
Many web developers like to prevent their viewers from copying their text. While I do...