Please read the whole question. I have a unique situation with several limitations that I would like to solve.
In my code, I have an expression tree that is compiled into Predicate<System.Type> . My goal is to load the assembly without blocking it (it will be displayed on the project assembly, constantly rebuild), apply this predicate in the list of its types and return a list of resulting name types:
// this is what I need: return assembly.GetTypes().Where(t => predicate(t)).Select(t => t.FullName);
This assembly must be loaded in another appdomain, because I want to unload it as soon as I get the information I need.
That's where it gets complicated. There are several issues that I am facing:
If I load the assembly into another appdomain and simply return an array of all its types so that I can apply the predicate in my main application, as soon as the types are redirected back to my main appdomain, I get a FileNotFoundException , stating that this assembly was not found. This causes the assembly to load only in another appdomain that I created. Downloading it also basically appdomain will defeat the goal.
If, as an alternative, I try to pass the predicate to another appdomain to apply it there and return an array of strings (full type name), I get a SerializationException: "Cannot serialize delegates over unmanaged function pointers, dynamic methods or methods outside the delegate creator assembly." because a predicate is a dynamic method (compiled from an expression tree).
Loading into the primary appdomain would not have any of these problems, but since it is not possible to unload the downloaded assembly without unloading the entire application, as soon as the assembly changes (after rebuilding), any attempt to load the assembly using the same name will throw an exception.
Context:
I am creating a plugin for ReSharper called Agent Mulder . The idea of ββthe plugin is to analyze the registration of the DI / IoC Container in your solution and help ReSharper figure out the use of types registered through the DI container (you can watch a short video on how it works here ).
For the most part, analysis of container registration is simple - I only need to find enough information to find out which specific types are affected. In this example with Castle Windsor: Component.For<IFoo>().ImplementedBy<Foo>() resulting type is obvious, so AllTypes.FromThisAssembly().BasedOn<IFoo>() - gives me enough information to indicate specific types, that will be affected by this line. However, consider this registration at Castle Windsor:
container.Register(Classes .FromAssemblyInDirectory(new AssemblyFilter(".").FilterByName(an => an.Name.StartsWith("Ploeh.Samples.Booking"))) .Where(t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dispatcher<>))) .WithServiceAllInterfaces());
( source )
Here the information depends on the predicate, which will be evaluated only at runtime.
Since all I can do is statically analyze this, I have in my hand a representation of the ReSharper AST (called PSI in ReSharper) lambda expressions from the Where clause. I can convert this AST to a LINQ expression tree and then compile it into a delegate.
My idea was to load the output assembly (defined by the FromAssembly* descriptor) using reflection and apply this delegate to the assembly types to get the type names (I only need the names). This will need to be reevaluated every time the assembly changes (at the moment I'm not worried about performance).
In conclusion, if someone cannot recommend a better way to determine the types affected by the predicate, I would like to know how to do this with reflection (unfortunately, I did not consider other metadata readers, because I would have to somehow convert AST lambda expression to predicate of another data type, and I don't know if 1 to 1 conversion exists).
Thanks for reading. This question will have 500 points when it becomes available.