3

I am creating a class library (MyLib), which contains a public class A. That class specifies a public methods M returning an instance of a class B from an external class library (ExtLib).

In order to use MyLib.A.M(), the user that will use my class library will have to reference both MyLib and ExtLib.

My question is, it that possible to somehow make the ExtLib.B class accessible directly through MyLib (ex: MyLib.B) so the user won't have to reference both libraries, but only MyLib?

STremblay
  • 125
  • 1
  • 7
  • How would a user have access to the external types if they didnt reference them? – Wjdavis5 Apr 13 '16 at 19:45
  • No. It's not possible. – Jcl Apr 13 '16 at 19:45
  • You can load the ExtLib assembly using Reflection. – Gosha_Fighten Apr 13 '16 at 19:46
  • 1
    @Gosha_Fighten or you could emit the type in runtime, but I don't think that's what the OP is asking for: if he doesn't have a use for `B` (as in: in a type-safe manner), then he actually doesn't need the `ExtLib` reference – Jcl Apr 13 '16 at 19:48
  • 2
    You might try this: http://stackoverflow.com/questions/1829531/how-do-i-merge-multiple-net-assemblies-into-a-single-assembly – Mike Cheel Apr 13 '16 at 19:49
  • 1
    Use [ILMerge](http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx) for this. – Greg Ferreri Apr 13 '16 at 19:53
  • @MikeCheel actually, ILMerge could be the best workaround given this scenario. Another possibility is making a full wrapper around the `B` object, but that's pretty much not reasonable if the intention is *to avoid a reference* (a reference that the main library has anyway) – Jcl Apr 13 '16 at 19:53
  • Also, depending on how froggy you are you and the type of assembly you could crack open the third party assembly in something like JustCompile, decompile and simply lift the code you need. I've done it before on the rare occasion =) – Mike Cheel Apr 13 '16 at 19:59
  • @MikeCheel ILMerge will generate another assembly. So, if changes are made in ExtLib, it'll be required to re-merge existing assembly. Emitting I think is a better choice. You can traverse through all B properties at JITing time and compile new ones if they are added. But, on the other side, there should be an interface implemented in the MyLib assembly that exposes new properties. So, MyLib should be changed too. – Gosha_Fighten Apr 13 '16 at 20:59

1 Answers1

1

You should just accept that your user should reference your assembly and the supporting one.

Yes, you can probably get ilmerge to work, so that the supporting assembly is incorporated in whole into your own assembly. But this completely ties your assembly's release schedule to the supporting assembly's. There would be no way for the supporting assembly to be updated for use with your assembly without re-releasing your own as well.

There is also the question of copyright and licensing. If you wrote the supporting assembly as well, I guess you should have no trouble at all. But otherwise, merging the supporting assembly with your own may at the very least be frowned upon by that assembly's author, if not prohibited outright.

Another unsavory option might be to return dynamic objects from your assembly's APIs instead of the types declared in the supporting assembly. This would of course have possible performance impacts, and would as well negate any possible compile-time type-safety that would otherwise be a normal benefit of using a language like C#. But it could be done.

If you really cannot stand the idea of the user adding a reference to the supporting library, a reasonable option from a software engineering point of view would be change your assembly's API so that it doesn't return types from the supporting library. They will still need that assembly at run-time if you use it, but at least the user's code wouldn't need the explicit reference. Instead, your API would return types your own assembly declares and which wrap the supporting assembly's types, possibly modifying those types' interfaces (removing unneeded members, adding new extensions, etc.) to suit your own users' needs better. That way the supporting assembly's types are hidden from view and so don't require an explicit reference by your users' assemblies.


IMHO it is worth taking note that your user is already referencing lots of other assemblies your assembly depends on, i.e. if nothing else, then the various .NET assemblies at least. Granted, many of these are required for any .NET code to work at all so the users' projects would have these references already, but they still represent additional assembly references. Other non-default .NET assemblies might or might not be required, depending on what else your own assembly uses and returns to the user's code. Regardless, this sort of thing is quite common and not really something one should be investing any significant amount of time trying to avoid.

Again, the fact is that the supporting assembly is going to be required at run-time anyway. So it does not seem like much of a hardship to require that assembly to be referenced by the user's own projects. Referencing assemblies that declare types one's own code depends on is just how .NET works. Why fight it? What compelling problem is it that could possibly motivate putting any real effort at all into avoiding this extra reference by users' projects?

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • I'll answer your question "What ... problem is it that could ... motivate putting ... effort into avoiding this reference" The answer is simple, school assignement with imposed constraint (afterward) where assembly A should use assembly B interface only, and assembly B use assembly C interface only. However, I already designed assembly C so that a few classes would be useful to both assemblies A and B, prior being informed of that constraint. So I was looking for a way to somehow "rename" thoses classes from C and maked them look like belonging to B. – STremblay Apr 14 '16 at 23:58
  • 1
    Ah. School assignment? Then the answer is easy: wrap the supporting assembly's type in your own assembly's type (i.e. the third option I suggest above). The constraint is already arbitrary, imposed for academic reasons; no reason to waste any time at all looking for a solution any more clever than that. (Besides, it's debatable whether using ilmerge would comply with the imposed constraint, as it would be tantamount either to taking the supporting assembly out of the equation entirely, or not changing the exposure of the type and its assembly, depending on how one looks at it.) – Peter Duniho Apr 15 '16 at 00:19
  • Thanks, I'll go ahead with the wrapper, that was my first idea, but was wondering it there was some kind of integrated "import" mechanism that could automatically include some part of an assembly into another one. The answer seems to be "no", so i'll go with the wrapper! – STremblay Apr 15 '16 at 12:21