简体   繁体   English

为什么引用的DLL与EXE一起存储

[英]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. 我在解决为什么将DLL复制到带有引用它的exe的文件夹时遇到了一些麻烦。 As I understand it, the reason I should make a DLL is to have reusable code. 据我所知,我应该制作DLL的原因是拥有可重用的代码。 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. 所以,如果我创建一个由25个应用程序引用的DLL(从而利用“可重用代码”),那么当我需要在DLL中添加更改功能(比如更新幕后发生的事情)时,我必须去打开并重新编译所有25个应用程序,以确保它们获得新功能。

A specific example I have is a DLL responsible for creating printed work order forms. 我的一个具体示例是一个DLL,负责创建打印的工单表单。 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. 我不认为我需要重建DLL,然后重建每个引用它的应用程序,但似乎是这种情况。 If I do not rebuild, then the applications continue to use the old version of the DLL. 如果我不重建,则应用程序继续使用旧版本的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) . 是 - 在全局程序集缓存(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". 允许使用EXE部署DLL的实际原因是允许“XCOPY部署”。 Plus it allows for "drop-in" libraries from NuGet and other sources that can be added without "installing" them. 此外,它允许从NuGet和其他来源“插入”库,可以添加而无需“安装”它们。 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. 对应用程序的Bolt-on扩展也更加简单,因为它们可以被复制,并且应用程序可以动态加载加载项而无需注册任何内容。

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". 其中很多都源于COM世界的痛苦, 每个 DLL都必须注册,如果你有多个不兼容的版本,你会发现自己处于“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. .NET通过允许使用可执行文件部署版本来放宽这些规则,但仍提供允许共享公共程序集的机制(GAC)。

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 您还可以阅读使用.NET Framework简化部署和解决DLL地狱的更多背景信息,了解.NET如何使用程序集解决版本问题

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: 根据你的情况,有可能只是将DLL复制到所有的新的应用程序,但也有可能会阻止它的某些因素:

  • If the assembly is signed 如果程序集已签名
  • If the application requires a specific version of the assembly 如果应用程序需要特定版本的程序集
  • etc. 等等

DLLs serve several purposes. DLL有多种用途。 One of the theoretical purposes is to allow multiple processes to share the same DLL. 理论目的之一是允许多个进程共享同一个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). 事实上,如果你在GAC中安装了一个DLL,那么.NET可以允许.NET实际将DLL加载到内存中(即同时运行多个进程,使用相同的DLL,不要每个人都得到自己的DLL内存中DLL的副本,就像其他DLL的情况一样)。

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. 在这种情况下,DLL的主要功能是作为某些给定功能的可再发行的存储库。 It's not important that multiple processes can use the same copy of a DLL. 多个进程可以使用DLL的相同副本并不重要。 Instead, it's only important that multiple processes have a convenient way to reuse the functionality in the DLL. 相反,重要的是多个进程可以方便地重用DLL中的功能。

Also note that changes to a DLL may or may not be beneficial. 另请注意,对DLL的更改可能有用也可能没有用。 Of course, one always hopes a newer version of a DLL is better. 当然,人们总是希望更新版本的DLL更好。 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. 使用给定版本的DLL进行全面测试的程序在与较新版本的同一DLL一起使用时可能保持可靠,也可能不保持可靠。

A newer version of the DLL is generally offered mainly to add features. 通常提供较新版本的DLL主要用于添加功能。 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. 并为每个程序提供自己的副本,以确保新版DLL中的意外更改干扰了仅使用旧版本测试的程序。

Finally note that even with the GAC it's possible to install multiple versions of a DLL. 最后请注意,即使使用GAC,也可以安装多个版本的DLL。 So if the DLL meets the necessary requirements, it's possible to significantly reduce the problems of DLL versions. 因此,如果DLL满足必要的要求,则可以显着减少DLL版本的问题。

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. 如果您将所有代码放在一个容器(TFS,GIT等)中,则没有理由不能将所有项目添加到单个主构建解决方案中并以这种方式分发代码。 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. 另一种选择是使用公共bin文件夹,并将所有项目输出到该主目录并从那里执行它们。 This would only require you to recompile the DLL and the other applications would pick this up immediately. 这只需要你重新编译DLL,其他应用程序会立即选择它。

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. 第三个选项是在DLL项目上有一个后期构建步骤,该步骤将文件复制到所有相关目录。 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. 使用DLL的一个较少讨论的优点是它们可以帮助您构建代码。

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. 将产品拆分为DLL可以让每个组件的开发人员更好地控制可访问性,因为您现在可以使用公共,私有和内部作用域。 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. 因此,例如,您可以在单个DLL中拥有一组紧密耦合的类,而不会让其他DLL中的代码滥用允许紧密耦合的接口。

Splitting a product into DLLs also forces you to think of build ordering when making dependencies between components. 将产品拆分为DLL还会强制您在组件之间建立依赖关系时考虑构建顺序。

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. 当然也存在各种方法,但是将项目拆分为DLL并依次构建它会迫使您非常明确地添加不遵循简单分层模型的依赖项。

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. 如果您计划使用第三方插件使您的产品可扩展,那么拥有一个定义应用程序及其插件之间接口的DLL通常会很有帮助。 That makes it easier for plugin developers to know what is / isn't in the supported API. 这使得插件开发人员更容易知道支持的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. 即使您只是使用可扩展性模型来组织由同一公司内的大型团队(或一组团队)开发的代码,相同的技术也会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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