1

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.

Luka Horvat
  • 4,283
  • 3
  • 30
  • 48

4 Answers4

1

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.

Community
  • 1
  • 1
Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • I want the main assemblies internals visible to the script, not the other way around. And I'm in a situation where I can't make the classes public because I want to reuse that console and I can't force everything to be public just for it to work. – Luka Horvat Jun 06 '12 at 09:54
  • @Darwin In that case, I don't think you will be able to do that. At the end of the day, your main assembly is simply an API to the generated ones, there is nothing wrong with exposing types publicly to be consumed. – Adam Houldsworth Jun 06 '12 at 09:56
  • Reflection might be very viable here but I'm not sure if it would work. If I skip making friends with assemblies and just pass things as object and then dynamically cast them to appropriate types I get via reflection... Will I not run into problems if a type I got contains another type that shouldn't be visible by default? – Luka Horvat Jun 06 '12 at 10:03
  • @Darwin Reflection has loads of potential problems. Alternatively, if you need to expose functionality in another assembly, in the main assembly mark them as `protected internal` and then derive from them in the generated assembly. Types in the generated assembly can then use this derived type. – Adam Houldsworth Jun 06 '12 at 10:05
  • This is turning out much harder that I should be... Is there a way to somehow modify the existing assembly instead of creating a new one each compile? That would be ideal since I could friend them AND avoid leaking memory. – Luka Horvat Jun 06 '12 at 10:07
  • @Darwin Changing the access modifier on types isn't difficult, and it seems you already have done some legwork to get the code compiling. This is simply a case of exposing correctly what you want to be exposed. I see no reason in types not being public if you are using them publicly. – Adam Houldsworth Jun 06 '12 at 10:13
  • But I really don't want to force every class to be public just so I can use it from one other assembly. There has to be a way to run code multiple times why still being able to access non-public classes. – Luka Horvat Jun 06 '12 at 10:43
  • @Darwin You don't necessarily need to, it'd just be the easiest solution. `protected internal` is a valid option, but is more of a workaround than actually solving the true issue. I know it is possible to amend/add attributes to _instances_ of types at runtime, but I haven't found any code for doing that against the current assembly yet. – Adam Houldsworth Jun 06 '12 at 10:45
0

You can add InternalsVisibleToAttribute to new assembly.

Denis Palnitsky
  • 18,267
  • 14
  • 46
  • 55
0

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

Ventsyslav Raikov
  • 6,882
  • 1
  • 25
  • 28
0

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.

Sander
  • 616
  • 1
  • 6
  • 17