为何类库中引用的外部DLL仍需在调用项目中添加?
问题分析
你遇到的核心问题是:即使将继承外部类的类型设为Friend/Private,.NET运行时在实例化该类型时,仍需加载其基类所在的外部程序集。这是因为.NET的类型系统要求,创建子类实例时必须解析并加载所有父类的程序集,无论子类的访问修饰符是什么。
解决方案
方案1:用适配器模式彻底隔离外部依赖(推荐)
不要让封装类直接继承外部类,而是在内部持有外部类的实例,通过委托调用其方法。这样外部程序集的依赖会被完全封装在类库内部,调用方无需引用或部署它。
修改后的代码示例:
Public Class MyCaller Public Shared Function UserLogin(ByVal username As String, ByVal password As String) As Boolean Return MyFunctions.Instance.UserLogin(username, password) End Function End Class Imports ExternalLibrary Friend Class MyFunctions Private Shared instanceField As MyFunctions = Nothing ' 内部持有外部类实例,不对外暴露 Private ReadOnly _externalService As ExternalClass Friend Shared ReadOnly Property Instance As MyFunctions Get If instanceField Is Nothing Then instanceField = New MyFunctions() End If Return instanceField End Get End Property ' 私有构造函数,确保仅内部实例化 Private Sub New() _externalService = New ExternalClass() End Sub Public Function UserLogin(ByVal username As String, ByVal password As String) As Boolean ' 将调用委托给外部类方法 Return _externalService.UserLogin(username, password) End Function End Class
方案2:将外部程序集嵌入类库(适用于必须继承外部类的场景)
如果因业务需求必须继承外部类,可以把外部DLL嵌入到类库的资源中,在运行时动态加载,避免调用方部署该DLL。
步骤如下:
- 将
ExternalLibrary.dll添加到类库项目,设置:- 复制到输出目录:不复制
- 生成操作:嵌入的资源
- 在封装类的静态构造函数中添加动态加载逻辑:
Imports System.Reflection Imports ExternalLibrary Friend Class MyFunctions Inherits ExternalClass ' 静态构造函数,在类第一次被访问时加载外部程序集 Shared Sub New() ' 替换为你的类库命名空间,确保资源名称正确 Dim resourceName = "YourClassLibraryNamespace.ExternalLibrary.dll" Using stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName) Dim assemblyBytes = New Byte(stream.Length - 1) {} stream.Read(assemblyBytes, 0, assemblyBytes.Length) Assembly.Load(assemblyBytes) End Using End Sub ' 其余原有代码保持不变... Private Shared instanceField As MyFunctions = Nothing Friend Shared ReadOnly Property Instance As MyFunctions Get If instanceField Is Nothing Then instanceField = New MyFunctions() End If Return instanceField End Get End Property Public Function UserLogin(ByVal username As String, ByVal password As String) As Boolean Return MyBase.UserLogin(username, password) End Function End Class
关键原理说明
.NET运行时在创建对象实例时,会递归解析该类型的所有基类、接口及依赖类型,并加载对应的程序集。即使子类是Friend/Private,只要在调用方进程中被实例化,就必须能找到基类所在的程序集——这就是你之前方案失败的根本原因。
内容的提问来源于stack exchange,提问作者Farhan Iqbal
相关产品推荐
相关产品推荐

