38

I have a helper project which I use in all the applications that I create. It contains some extension methods and a bunch of generic helper classes, controls etc. I update/extend the helper project from time to time. These are usually small and unrelated projects, and I am the only person working on all of them.

I tried two approaches for using it

  • add .cs files directly (Add as link) to each project where I use them
  • compile it as .dll and add it as reference

I see some benefits and drawbacks of these approaches.
The first one:

  • is simpler, because the helper classes get compiled into the exe file, therefore I can often very easily provide just a single .exe file that will work just fine. Because I add as link, I can be pretty sure that whenever I build any project that uses the helper, the helper files will be the latest version.
  • is even simpler, because I can separate the files, so that my extension methods that run fine on .NET 4.0 can be referenced separately from the ones that require .NET 4.5, which means that the app as a whole can run on .NET 4.0
  • Allows to debug through the code, with all the benefits of breakpoints etc etc...
  • doesn't seem to be 'best practice'

The second one:

  • appears to be the right approach, but:
  • requires me to deliver a separate .dll file, which for some reason is much more difficult for users (they tend to share my programs without the .dll, which then crashes on startup)
  • as it gets compiled into a single .dll, it will require the highest version of .NET - many of my users don't have .NET 4.5 and only some elements of my helper class require this, which means I can be forcing some people to update their systems for no reason
  • I also need to make sure that whenever I update any of my programs, I also deliver the .dll file - even though I don't know if it has been changed since the last version, or not (it could have been, but it could as well be the same version). I cannot see a simple way to determine that, without keeping track of assembly version, which is additional work. For now, when I update my programs, I only deliver updated exe, and I like to keep it small and low profile.

So, what is the actual benefit for using the .dll file here? Please note, that I am the only person editing code of all the applications and the helper files.


Also, to clarify - the apps are usually very little, whereas the code contained in the helper classes is completely generic to all of them (some simple string-comparison, paths or XML operations etc)


Actually, someone made me realize just now that there's a third option. As I have the helper code in a separte project, I can add this project to solutions of each of my separate applications - which works kind of like 'Add as link' for single files, except I only add a single project... But as noticed by Doc Brown, this essentially means that .dll will need to be added to the project anyway...

Yet another thing which is kind of in favour of not using the dll files is the ability to debug through the helper class actively...

9
  • 3
    You're right, and I am even doing it, as it helps in case of higher .NET requirements... But I don't like doing it... An installer for 40kb app is a bit of an overkill:)
    – Bartosz
    Commented Sep 11, 2015 at 12:46
  • 3
    Well you can always use something like Costura, it is a tool for merging DLLs. You can merge all the dependencies to the EXE, keeping a single file and allowing you to use any libraries necessary. This can be automated to the build process, for simplicity.
    – Kroltan
    Commented Sep 11, 2015 at 14:49
  • 2
    When you add a project to a solution, you still have to deploy the DLL of this project, with all the drawbacks you listed above.
    – Doc Brown
    Commented Sep 11, 2015 at 16:15
  • 2
    @DocBrown - holy crap, you're right:)
    – Bartosz
    Commented Sep 11, 2015 at 17:01
  • 1
    Linking .cs files or projects can have another drawback. If you're using these shared files in many projects, and one project requires a breaking change to your shared libraries, you now need to refactor your other projects. Referencing dlls insulate you from that if there's no reason for your code to require the updated logic. I've been part of development teams that have run into this issue when the shared projects involve things like custom authentication. The customer wants to try a change for a new application, and now you need to version your common library somehow. Using dlls do that.
    – Ellesedil
    Commented Sep 11, 2015 at 20:09

6 Answers 6

13

You already spotted most of the pros and cons. Using cs files as references is indeed more lightweight and often easier to manage. However, I recommend to use this approach exclusively when your cs files are fully self-contained and do not have any special build requirements.

Using separate DLLs

  • will make dependencies to other utilities or libraries explicit (so as long as you do not have such dependencies, it will work fine)

  • will allow you to define specific build configurations (for example, if a class only works in x86 configuration, or needs at least .NET 4.0, the build configuration of the assembly makes this requirement explicit).

So especially if you have lots of single-class, self contained components, using reference to files is fine, but if you have components referencing other components, or specific build requirements, I would recommend to use DLLs.

To mitigate the problems with managing many separate DLLs, you can either create an installer package, or utilize ILMerge, which can embed a set of assemblies into a single executable. In our environment, we deal with the problem differently, by using a deploy script for each application. This script makes sure all needed DLLs are always delivered to production when a new application release is published.

14
  • Ok, thanks a lot - so, do I understand correctly, that as long as my helper classes do not reference any other external dlls (contain only standard .NET code) it is not an abomination to simply link them?
    – Bartosz
    Commented Sep 11, 2015 at 12:09
  • @Bartosz: no exernal DLLs, and each helper class should ideally not use any other helper class, or only other helper classes which are stored in the same file. To be honest, to some degree you can manage the situation where helper class A needs helper class B stored in a separate file, but this approach does not scale well.
    – Doc Brown
    Commented Sep 11, 2015 at 12:17
  • 1
    @PeterK. - yep, and I did:)
    – Bartosz
    Commented Sep 11, 2015 at 13:54
  • 1
    @whatsisname: not that this could not work. However, to me it does not sound like a solution which would simplify things, more like one which can cause unexpected problems ;-)
    – Doc Brown
    Commented Jun 28, 2016 at 16:17
  • 1
    @Ozkan: in our environment, it is just xcopy deployment to some network share (with some extra steps for backing up the former version and making sure noone uses the program currently - which is achieved by an attempt to rename the deployment folder first). It knows which dlls to deploy because we hardcode the list of the required DLL into the script - no magic behind it. This solution is not perfect, but works for us in most cases, except for programs which are used heavily by dozens of users.
    – Doc Brown
    Commented Jan 4, 2019 at 8:43
12

DLLs are handy when an application is large and there are pieces that require updates, but not the entire application. So, if you're writing MS Word, it's handy to have the spell-check code in a DLL that can be updated without having to update the entirety of MS Word. If what you're writing is a small utility app (or a series of self-contained apps that happen to all use the same code) it doesn't make much difference whether the code is embedded in the app(s) or not.

2

You have pretty much summed it up in your question, I only have a couple of points to add.

Mono Options is a great example of a NuGet package that uses the first approach very well.

Alternatively, if you decide to use dlls you can use tools like Costura to embed that reference in your executable as an embedded resource. To use it just add the Costura.Fody package:

Install-Package Costura.Fody
3
  • Actually, there's one more thing - with embedded project or files added as link, you can also actively debug the code all the way through the helper file...
    – Bartosz
    Commented Sep 11, 2015 at 16:59
  • 1
    @Bartosz I think you can still debug "all the way through" without the "helper file", as long as you have the correct pdb file.
    – Zack
    Commented Sep 11, 2015 at 19:14
  • I tried the Costura thing and I really like it!
    – Bartosz
    Commented Sep 15, 2015 at 11:55
2

Whether a dll is more beneficial or not depends on several factors:

  1. The size of the code (when compiled).
  2. How many exes use it.
  3. How often you intend to update the code.
  4. Whether or not the exes are intended to be kept together or exist completely seperately.

The purpose of a shared library is to take code that is common to multiple executables and centralise it so that all executables share a copy. This is intended to save space and make code easier to update.

If the amount of code in your helper class is very small, it may not be worth moving it to a dll as the overhead of the code being in a dll may counteract the space saving benefit of having it centralised.

Additionally, if you're only making a few executables, the size of the code in each executable may be small enough to not be an issue. However, the more executables you have using the same code, the more beneficial it would be to have the code moved into a dll.

As a simplified example, say your helper class compiles to 128 bytes in an exe file, but when moved to a dll, the dll is 512 bytes. If you only have 3 executables, you would be saving space by including the code in the executables. However if you had 5 executables, you would then be at the point where you would be better off having a dll because the combined space taken up by 5 copies of the code (5 * 128 = 640 bytes) is more than the space taken up by having the code in a dll (512 bytes).

Now say for example you find a bug in your helper code. If you compiled all your executables with the code baked in, you have to recompile every single executable and then redistribute the recompiled versions. If you compiled the code to a dll, you would only have to recompile and redistribute the one dll, and the bug would automagically be fixed for all of the executables using it.

Lastly, for a program to find a dll it has to know where to look for the dll. If you are keeping all your executables together, you can just put the dll in the same directory and they'll all find it straight away. If you're intentionally keeping them separated, it becomes harder to coordinate them to use the same dll.

1

Your third option is the most appropriate (add it as a separate "class library" project to the solution). This combines the benefits of all approaches:

  • Your "helper project" is always up to date on all different projects.
  • You can reference the code of the project when you want to quickly see changes.
  • You can build it for the correct .NET version each time.
  • You can embed a DLL in an exe anyway, so don't worry about that you can just have that as part of your build.

We do this all the time and I can't do anything but recommend this approach.

Another fourth alternative you have not mentioned is to put it on a private NuGet repository which would let you version it correctly and reference it without the extra project in each solution.

1
  • 2
    Hm, it appears to me that when I add it as a project to the solution and then reference this project in other projects, then it is still created as a separate .dll rather than being embedded... Is there anything I should specify?
    – Bartosz
    Commented Sep 11, 2015 at 20:33
1

As a developer, I always like to include the reference of utility's solution to my application as it allows me debug the code (and spot possible bugs in Utility too!) plus any changes made to the utility are automatically included in the application.

So, actually the decision depends on how mature the Utility is! If you are uncertain about the Utility bugs, then you should always include the .cs file of that utility to find out the bugs.. But if you are sure that Utility is mature enough and it will not be returning result with any bugs and there is no scope for enhancement in the Utility, you can go ahead and include the DLL file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.