I've been searching for this for quite a while with no luck so far. Is there an equivalent to Java's ClassFileTransformer
in .NET? Basically, I want to create a class CustomClassFileTransformer
(which in Java would implement the interface ClassFileTransformer
) that gets called whenever a class is loaded, and is allowed to tweak it and replace it with the tweaked version.
I know there are frameworks that do similar things, but I was looking for something more straightforward, like implementing my own ClassFileTransformer
. Is it possible?
EDIT #1. More details about why I need this:
Basically, I have a C# application and I need to monitor the instructions it wants to run in order to detect read or write operations to fields (operations Ldfld
and Stfld
) and insert some instructions before the read/write takes place.
I know how to do this (except for the part where I need to be invoked to replace the class): for every method whose code I want to monitor, I must:
- Get the method's
MethodBody
usingMethodBase.GetMethodBody()
- Transform it to byte array with
MethodBody.GetILAsByteArray()
. Thebyte[]
it returns contains the bytecode. - Analyse the bytecode as explained here, possibly inserting new instructions or deleting/modifying existing ones by changing the contents of the array.
- Create a new method and use the new bytecode to create its body, with
MethodBuilder.CreateMethodBody(byte[] il, int count)
, whereil
is the array with the bytecode. I put all these tweaked methods in a new class and use the new class to replace the one that was originally going to be loaded.
An alternative to replacing classes would be somehow getting notified whenever a method is invoked. Then I'd replace the call to that method with a call to my own tweaked method, which I would tweak only the first time is invoked and then I'd put it in a dictionary for future uses, to reduce overhead (for future calls I'll just look up the method and invoke it; I won't need to analyse the bytecode again). I'm currently investigating ways to do this and LinFu looks pretty interesting, but if there was something like a ClassFileTransformer
it would be much simpler: I just rewrite the class, replace it, and let the code run without monitoring anything.
An additional note: the classes may be sealed. I want to be able to replace any kind of class, I cannot impose restrictions on their attributes.
EDIT #2. Why I need to do this at runtime.
I need to monitor everything that is going on so that I can detect every access to data. This applies to the code of library classes as well. However, I cannot know in advance which classes are going to be used, and even if I knew every possible class that may get loaded it would be a huge performance hit to tweak all of them instead of waiting to see whether they actually get invoked or not.
POSSIBLE (BUT PRETTY HARDCORE) SOLUTION. In case anyone is interested (and I see the question has been faved, so I guess someone is), this is what I'm looking at right now. Basically I'd have to implement the profiling API and I'll register for the events that I'm interested in, in my case whenever a JIT compilation starts. An extract of the blogpost:
- In your ICorProfilerCallback2::ModuleLoadFinished callback, you call ICorProfilerInfo2::GetModuleMetadata to get a pointer to a metadata interface on that module.
- QI for the metadata interface you want. Search MSDN for "IMetaDataImport", and grope through the table of contents to find topics on the metadata interfaces.
- Once you're in metadata-land, you have access to all the types in the module, including their fields and function prototypes. You may need to parse metadata signatures and this signature parser may be of use to you.
- In your ICorProfilerCallback2::JITCompilationStarted callback, you may use ICorProfilerInfo2::GetILFunctionBody to inspect the original IL, and ICorProfilerInfo2::GetILFunctionBodyAllocator and then ICorProfilerInfo2::SetILFunctionBody to replace that IL with your own.
The great news: I get notified when a JIT compilation starts and I can replace the bytecode right there, without having to worry about replacing the class, etc. The not-so-great news: you cannot invoke managed code from the API's callback methods, which makes sense but means I'm on my own parsing the IL code, etc, as opposed to be able to use Cecil, which would've been a breeze.
I don't think there's a simpler way to do this without using AOP frameworks (such as PostSharp). If anyone has any other idea please let me know. I'm not marking the question as answered yet.