Well, personally I have created extension methods on the ILGenerator
class with the same names as the opcodes, with the right parameters, so that I don't have to look up the documentation all the time. These extension methods also return the generator object it was invoked on, so I can do call chaining.
For instance, to implement a ToString method, I could do this:
var il = method.GetILGenerator();
il
.ldarg_0()
.ldfld(nameField)
.ret();
I've also created a similar class, named IL, that has methods that return an IL.Element object, which I can collect into a collection or similar, manipulate, etc. before finally emitting the code. This allows me to create "code producers" and not just "code emitters". Subtle difference, but I've found the "give me the code I can emit" has been more useful than "emit the code into this ILGenerator".
Thus, I could do this:
IL.Element[] il = new IL.Element[] {
IL.ldarg_0(),
IL.ldfld(nameField),
IL.ret()
};
and then:
method.GetILGenerator.Emit(il); // also an extension method
Of course, I've added some extra extension methods that makes it easier for me to emit code as well, such as "call_smart", that figures out which of the call instructions to emit based on the type of method (static, virtual, etc.).
Other than that, I don't know of any other tools, so perhaps I didn't really answer your question.
My code is available, if you want to look at it. Leave a comment, and I'll edit the answer and dig up a repository url for you.