How can I use the assembly resolver correctly?

626 views
Skip to first unread message

Yves Goergen

unread,
Mar 25, 2014, 3:07:55 PM3/25/14
to mono-...@googlegroups.com
I have the following test environment: An EXE application that references a DLL library. No further references other than the framework. Both files are in the same directory, but not in the current working directory. The EXE file defines a class that inherits from a class defined in the DLL. I need to open all assemblies and investigate their types, base types etc. I have opened both files like this:

// Instance member, used for all files to read
private IAssemblyResolver asmResolver = new DefaultAssemblyResolver();

// Read a file
((DefaultAssemblyResolver) asmResolver).AddSearchDirectory(Path.GetDirectoryName(fileName));
var moduleDef = ModuleDefinition.ReadModule(fileName, new ReaderParameters() { AssemblyResolver = asmResolver });

The EXE file comes first, then the DLL. Even if it would work the other way around, this is a scenario that needs to work as I can't figure out the referencing hierarchy all the time. The call to AddSearchDirectory makes Cecil find the referenced library at all, a thing I'd have expected out of the box, since at runtime it's the same. But I have the impression that I get two independent instances of the DLL assembly. One that I know of any investigate, and another one that Cecil uses internally as reference for the EXE file. I thought that using a common resolver instance should help, but it doesn't seem to be the case.

It's really hard to figure out how to use this stuff if there's no documentation at all. It's been a guesswork from the start and now I'm stuck.

Even if I need to write my own code for the assembly resolver, what should it do? There's an interface, but it comes with no meaning, only method names.

Jb Evain

unread,
Mar 25, 2014, 4:34:40 PM3/25/14
to mono-...@googlegroups.com
Yves,

interface IAssemblyResolver {
AssemblyDefinition Resolve (AssemblyNameReference reference);
}

This has no meaning? :)

A documentation would read like: An assembly resolver is responsible
for resolving references to an assembly into its definition.

(Which is arguably the same has the above, just a different language :)

You can also have a look at the default implementation:

https://github.com/jbevain/cecil/blob/master/Mono.Cecil/BaseAssemblyResolver.cs
https://github.com/jbevain/cecil/blob/master/Mono.Cecil/DefaultAssemblyResolver.cs

It's not a completely straightforward process, if you want a complete
understanding you can checkout and build Cecil in your project and
step into the code.

--

Now to answer your question.

The default resolver only caches the assemblies it resolves. Not those
you read yourself. Meaning, if you use ModuleDefiniton.ReadModule or
AssemblyDefinition.ReadAssembly, those won't be cached for you.

You can easily implement that by creating your own class extending
DefaultAssemblyResolver, and calling RegisterAssembly on existing
assemblies.

Jb
> --
> --
> --
> mono-cecil
> ---
> You received this message because you are subscribed to the Google Groups
> "mono-cecil" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to mono-cecil+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Yves Goergen

unread,
Mar 26, 2014, 6:05:22 PM3/26/14
to mono-...@googlegroups.com
Am Dienstag, 25. März 2014 21:34:40 UTC+1 schrieb Jb Evain:
This has no meaning? :)

Well, to you it certainly has a meaning. To me it might mean a lot less or something different.
 
A documentation would read like: An assembly resolver is responsible
for resolving references to an assembly into its definition.

The documentation could go more into details of the behaviour or expectations which is not obvious from the name alone. Like the purpose of the cache.
 
(Which is arguably the same has the above, just a different language :)

Which would be a stub, not a real documentation. Robots are generating such stubs.
 
It's not a completely straightforward process, if you want a complete
understanding you can checkout and build Cecil in your project and
step into the code.

That's what I do all the time. It already helps a lot, but not always.
 
The default resolver only caches the assemblies it resolves. Not those
you read yourself. Meaning, if you use ModuleDefiniton.ReadModule or
AssemblyDefinition.ReadAssembly, those won't be cached for you.

This is a very good start for a documentation. :-)
 
You can easily implement that by creating your own class extending
DefaultAssemblyResolver, and calling RegisterAssembly on existing
assemblies.

Thank you, that works fine. I'm just wondering why that method isn't public so I could simply call it on DefaultAssemblyResolver. Now I need to create a class whose only purpose is to make a non-public member public.
Reply all
Reply to author
Forward
0 new messages