简体   繁体   中英

Why are referenced DLLs stored with the EXE

I'm having some trouble wrapping my head around why a DLL is copied into the folder with the exe that is referencing it. As I understand it, the reason I should make a DLL is to have reusable code. So, if I create a DLL that is referenced by 25 applications (thereby utilizing the "reusable code"), then when I need to add change functionality in the DLL (say, updating something that happens behind the scenes), I have to go open and recompile all 25 applications to make sure they get the new functionality.

A specific example I have is a DLL responsible for creating printed work order forms. The layout and look of the Work Order form has changed, but none of the contained information has changed. In this case, I only need to make some changes to the underlying form creation code, but no change to the implementation of that code (the exact same methods and properties are used). I wouldn't think that I would need to go rebuild the DLL, then go rebuild every application that references it, but that seems to be the case. If I do not rebuild, then the applications continue to use the old version of the DLL.

Is there a way around this? Am I thinking about it incorrectly? Should I be doing something else? Do I just completely misunderstand all of this? Thanks for any help you can provide.

Is there a way around this?

Yes - install the library in the Global Assembly Cache (GAC) . That way in can be used by many applications.

Read How the Runtime Locates Assemblies to better understand how references are loaded. The practical reason for allowing DLLs to be deployed with the EXE is to allow "XCOPY Deployment". Plus it allows for "drop-in" libraries from NuGet and other sources that can be added without "installing" them. Bolt-on extensions to applications are also much simpler because they can just be copied in, and the app can dynamically load add-ins without having to register anything.

A lot of it stems from the pain of the COM world, where every DLL had to be registered, and if you had multiple versions that weren't compatible, you found yourself in "DLL Hell". .NET relaxed those rules by allowing versions to be deployed with the executable, but still providing a mechanism (the GAC) to allow for common assemblies to be shared.

You an also read Simplifying Deployment and Solving DLL Hell with the .NET Framework for more background on how .NET uses assemblies to solve versioning problems

In your case, it may be possible to just copy the DLL to all of the new applications, but there are certain factors that may prevent it:

  • If the assembly is signed
  • If the application requires a specific version of the assembly
  • etc.

DLLs serve several purposes. One of the theoretical purposes is to allow multiple processes to share the same DLL. And in fact, if you install a DLL in the GAC, that can allow .NET to actually load the DLL once into memory (ie multiple processes running at the same time, using the same DLL, don't wind up each getting their own copy of the DLL in memory, as would be the case for other DLLs).

But another purpose is simply for code-reuse. In this scenario, the DLL's main function is to serve as a redistributable repository for some given functionality. It's not important that multiple processes can use the same copy of a DLL. Instead, it's only important that multiple processes have a convenient way to reuse the functionality in the DLL.

Also note that changes to a DLL may or may not be beneficial. Of course, one always hopes a newer version of a DLL is better. But changes to code always mean an opportunity to add new bugs to the code. A program that has been thoroughly tested with a given version of a DLL may or may not remain reliable when used with a newer version of the same DLL.

A newer version of the DLL is generally offered mainly to add features. Of course, some bugs may be fixed in the process but again, if the program has been tested with the older version and is currently working, the new bug fixes are probably not critical. At the same time, the program written with the older version probably won't have any practical way to take advantage of the newer functionality.

Disk space is cheap, and memory almost as cheap. And giving each program its own copy ensures against unexpected changes in the new version of the DLL interfering with a program that was only tested with an older version.

Finally note that even with the GAC it's possible to install multiple versions of a DLL. So if the DLL meets the necessary requirements, it's possible to significantly reduce the problems of DLL versions.

It sounds like you have a build automation problem (or lack of). If you have all the code in one container (TFS, GIT, etc.) then there is no reason that you can't add all of the projects to a single master build solution and distribute the code this way. That way - you just go in and recompile the main solution and the files get pushed to all of the apps.

Another option is to use a common bin folder and have all the projects output to that main directory and execute them from there. This would only require you to recompile the DLL and the other applications would pick this up immediately.

A 3rd option would be to have a post build step on the DLL project that copied the file to all of the directories in question. I would not recommend this approach as it will be a nightmare to maintain.

All of this does not take into consideration how you consume / deploy your applications and how many users / environments you have to take into consideration.

One of the lesser-discussed advantages of using DLLs is that they help you structure your code.

Splitting a product into DLLs gives the developers of each component more control over accessibility, as you now have public, private, and internal scopes to work with. So for example you can have a tightly-coupled set of classes within a single DLL without letting code in other DLLs abuse the interfaces that allowed that tight coupling.

Splitting a product into DLLs also forces you to think of build ordering when making dependencies between components.

You could of course try to just be diligent and disciplined about maintaining the layers in your high-level design, but nothing beats a build break to let you know when you've added a dependency that shouldn't be there. Of course there are ways around as well, that but splitting a project into DLLs and building them sequentially forces you to be very explicit about adding dependencies that don't follow a simple layered model.

And if you plan to make your product extensible with third-party plugins, it is often helpful to have a single DLL that defines the interface between the application and its plugins. That makes it easier for plugin developers to know what is / isn't in the supported API. And the same techniques can be helpful even if you're just using an extensibility model to organize code developed by a large team (or set of teams) within the same company.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM