I have an extension method that looks like the following:
//[MethodImpl(MethodImplOptions.NoOptimization)]
public static IEnumerable<char> TakeWhile(this BinaryReader reader, Func<int, bool> condition)
{
while (condition(reader.PeekChar()))
{
cha开发者_开发问答r c = reader.ReadChar();
yield return c;
}
}
I use this method when parsing a file with a BinaryReader to skip a block of whitespace characters, amongst other things. What i have found is that the JIT compiler is optimising it out, when i call it like so:
// Skip white space
this.reader.TakeWhile(IsWhiteSpace);//.FirstOrDefault();
I have tried adding the [MethodImpl(...)] attribute to instruct the JIT compiler not to optimise out the method, but it does not work. Now obviously i could write another implementation of this which manipulates the underlying stream buffer position but out of curiosity i would like to know why this is so.
The only ways i have found to prevent the optimisation is to use the IEnumerable results (eg - via a call to .FirstOrDefault() as commented above) or copy the code into the calling method. I have tried preventing optimisation of the calling methods, using the MethodImplAttribute, but this does not work. Strangely, optimisation is turned off completely under the Debug build so it shouldn't be occuring in any situation. Does anyone know another way to prevent the optimisation?
No, the JIT isn't optimizing it out. However, none of your code will be executed - because you're ignoring the returned value. Until the first call to MoveNext()
, none of the code in the iterator block is run. This has nothing to do with the JIT, and everything to do with how iterator blocks work.
You may want to read my articles on iterator blocks (basics, implementation details) and Eric Lippert's "psychic debugging" blog post (part 1; part 2).
Note that calling FirstOrDefault()
will only read the first character. It sounds like you really want to consume the whole stream until the condition fails - which means using something like Count()
which will iterate over the entire returned sequence.
Alternatively - and preferrably IMO - write an "active" method with a void return type to do this. If you're not interested in the return value of a method, that's a signal that it's probably not an ideal method to call. (That's not always the case, but it usually is.)
精彩评论