Making assemblies internals visible to another assembly at runtime

4.5k views Asked by At

So I have been looking for a way to do this for a while and every time I find something, it leads to a different problem.

Basically, I have a game console. The console runs snippets of C# code. The compiled assembly needs to be a friend of the current assembly so that the console would know about all the types in the current assembly and could manipulate them.

Problem one: Every time you run a console command, a new assembly is generated (I would love to avoid this if anyone knows how) and for it to be a friend assembly it needs to have the same name as the last one. Unfortunately you can't unload the previous assembly so the new one can't overwrite it. This forces me to use AppDomains.

Problem two: If I make each assembly use a separate AppDomain and then unload the last one, it works but I can't manipulate the objects from the current AppDomain because they don't derive from MarshalByRef so when I pass them as parameters to the script it tries to serialize them. I don't like AppDomains.

So I figured the most painless way would be to just generate assemblies in the same AppDomain with different names and somehow set them as friend assemblies at runtime.

I do realize that this might not be possible so any other alternatives a welcome.

EDIT: To make it more clear. Script needs to access the main/parent assemblies internals. Not the other way around. I can't make everything public in the main assembly because I want the code to be reusable.

4

There are 4 answers

5
Denis Palnitsky On

You can add InternalsVisibleToAttribute to new assembly.

8
Adam Houldsworth On

If you are generating these assemblies, why not just make the items you want public public instead of internal?

Alternatively, mark the exposable types as protected internal and create derived classes in the generated assembly (assuming the generated assembly references the main assembly). This will then allow your generated assembly to use its derived class, and that derived class will have access to the main assembly via protected members. Neither of these make your members generally "public".

You can use the InternalsVisibleToAttribute, but this is at compile-time. However, it sounds like you are dynamically compiling an assembly from code-snippets, so you should be able to also compile in any attributes you want.

I didn't realise you wanted the main assembly to be visible to the generated assemblies. As the following question's answer explains, you can affect the attributes of a given instance, but not statically against the type.

Can attributes be added dynamically in C#?

Of course, your generated code could always use reflection to get the types out.

0
Ventsyslav Raikov On

It doesn't seem possible. You can just generate the members of each assembly as public - since the assembly is dynamically generated this should not be an issue

0
Sander On

I'm thinking about a problem that resembles yours and I'm considering some kind of proxy assembly that exposes public methods to the internals of the main assembly.

Assemblies:

  • Main: with internal components and internals visible to a proxy assembly;
  • Proxy: with public methods to indirectly access the internal of the main;
  • Consumer: can access the proxy to modify the main.

In my case, my Main assembly is a reusable component and I've got two kinds of consumers. The first kind is just using the reusable components inside my Main and thus has only access to the public members of the Main assembly. The second consumer is the test assembly testing the first mentioned consumer assembly. This assembly typically wants to mock some internals in the Main assembly and therefore is using the Proxy to access these internals.

It might be kind of an overhead, especially when generating assembly, but it keeps concerns nicely separated.