views:

176

answers:

2

When you write an iterator function in C#, using yield syntax, the compiler internally translates your function into a class. So, if I write something like this:

IEnumerator<int> MyIterator () {
  for (int i = 0; i < 10; i++)
    yield return i;
}

Invoking MyIterator() constructs a class with a private field for i, instead of using a stack variable.

Now for the question: I want to find a way to locate the field used to store i's value. The reason is a little involved:

I'm using iterator functions for cooperative threading. I write simple code like this in an iterator, in order to suspend execution of a function until an asynchronous operation has completed.

Future<string> f;
yield return file.readLine(out f);
string line = f.Result;

When those three statements are executed, the readLine function is invoked and stores a future into the 'f' field. The iterator function is then suspended, and wakes back up when the 'f' Future has had a result stored into it, at which point I can retrieve the result.

What I want to be able to do, is this:

string line;
yield return file.readLine(out line);

Under normal circumstances, this wouldn't be possible in .NET, since there is no way to guarantee that a stack variable stays alive long enough for me to be able to write to it.

However, knowing that iterator functions store all their locals inside of fields, I can theoretically do this by holding a reference to the iterator (keeping it alive) and to the field itself, so that when the readLine operation completes, I can store the result directly into the field.

The problem is that the CLR doesn't seem to give me a way to do this.

If I have an 'out' or 'ref' parameter, I can use unsafe C# or raw MSIL to convert that parameter into a raw pointer, a reference, or a TypedReference. Unfortunately, it's not legal to store any of those three types in a field - even if you trick the compiler into letting you do it, the bytecode verifier won't let you execute the code. This is most likely because storing a reference to a stack variable would be inherently unsafe.

So what I'm looking to do is write a function that takes an out/ref parameter, and searches the calling iterator's fields to find a corresponding field. Once it has the field, it stores a reference to the iterator and field into a wrapper type and associates the wrapper with an asynchronous operation.

Given the overhead involved in runtime reflection in .NET, I suspect that this isn't possible without either preprocessing my source code or post-processing my assemblies after compilation.

However, I'd love to hear some suggestions for alternate solutions. :) Any ideas?

+1  A: 

Monkeying with the iterator's fields is begging for trouble. Wouldn't it be simpler to use a member of a class that you specify in the iterator signature? Either by passing it in or out? Basically involving some kind of simple wrapper class along the way?

class MyWrapper {
    public string Line {get;set;}
}

allowing you to talk to Line quite safely, simply via a MyWrapper object reference?

I didn't understand all of the question, so that is the best I can say...

Marc Gravell
Future<string> in the example more or less serves the purpose you describe. Having to unbox my value from a container every time is a pain, so I'd like to skip the step and write directly to the field if I can.The semantics of modifying the iterator's fields seem clear to me - if you look at the generated IL for an iterator, it's perfectly safe to modify the locals as long as you do it in a sane way.
Kevin Gadd
A: 

I finally found a solution that meets my needs here, and what do you know - it involves LINQ.

A blog post on .NET mentioned offhand how you can convert any expression lambda into an Expression<> object if you know the result type of the expression. Given that, it turns out that you can take an expression like this:

() => this.Foo.Bar

And walk through the nodes to end up with a MemberInfo (for 'Bar') and a 'this' object (for 'this.Foo'). Given these two values, you can bind directly to a field or property specified at compile time. In the case of a property, you can do this very efficiently by retrieving the Get and Set methods of the property from the MemberInfo and converting them into strongly-typed delegates, making the cost of reading/writing that property very low.

Best of all, this works perfectly with automated refactoring and source code searches because it's putting the compiler's muscle to use for you, and it doesn't require any modifications to existing code in order to allow binding.

The only downside is that it's very difficult to bind to fields/properties of a struct, but I don't consider that a particularly relevant use case anyway.

Anyone looking to solve this or a similar problem can view the source code here:

http://code.google.com/p/fracture/source/browse/trunk/Squared/Util/Bind.cs

Kevin Gadd