加载未引用的Dll

时间:2019-06-28 11:51:50

标签: c# dll .net-assembly

我正在尝试动态加载deleteBuffer

已安装System.Data.SqlClient Nuget,但在项目中没有对其的引用。

我不知道nuget目录的正确路径。

有没有办法动态地做到这一点?

这是我的代码

System.Data.SqlClient

这是我的运行方式

internal static Type GetFastType(this string typeName, string assembly)
{
    if (string.IsNullOrEmpty(assembly))
        throw new Exception("AssemblyName cannot be empty");

    if (!assembly.ToLower().EndsWith(".dll"))
        assembly += ".dll";
    var key = typeName + assembly;
    if (CachedStringTypes.ContainsKey(key))
        return CachedStringTypes.Get(key);

    // Assembly.LoadFrom(assembly) // throw exception as the dll is not found
    if (!CachedAssembly.ContainsKey(assembly))
        CachedAssembly.Add(assembly, Assembly.LoadFrom(assembly));

    return CachedStringTypes.GetOrAdd(key, CachedAssembly.Get(assembly).GetType(typeName, true, true));
}

3 个答案:

答案 0 :(得分:1)

必读:

阅读此MSDN文章:Best Practices for Assembly Loading

简而言之:

似乎您假设System.Data.SqlClient.SqlConnection类始终存在于System.Data.SqlClient.dll内部。

这是一个错误的假设:

  • NuGet程序包不是.NET程序集。
  • NuGet程序包不与.NET程序集或名称空间一对一映射。
  • NuGet程序包可以包含多个程序集。
  • NuGet程序包可以包含零个程序集。
  • NuGet软件包可以包含根本没有定义任何类型的程序集!
    • 它们可以是仅包含资源或其他嵌入式项目的程序集
    • 它们可能是使用Type-Forwarding重定向该程序集中先前存在的类型的程序集和其他程序集。只有JIT使用此功能,但是不使用反射。
      • 并且这些“转发到”程序集也不必存在于NuGet程序包中:它们可以是运行时内置的“内置”程序集,例如mscorlib.dllSystem.Data.dll) 。
    • 当基类库已经提供了这些类型时,它们可能是不提供任何类型的存根程序集-NuGet包仅存在以为其他平台提供这些类型。
      • 您正在处理的情况。
  • 根据项目的目标(.NET Framework,.NET Standard,.NET Core等),NuGet程序包可以产生非常不同的效果

您的代码无法假定特定的类位于特定的程序集文件中-这打破了.NET通过类型转发的向后兼容性的概念。

您的情况...

在您的情况下,您的代码假定System.Data.SqlClient.SqlConnection存在于名为System.Data.SqlClient的程序集文件中。这种假设在许多情况下是错误的,但在某些情况下是正确的。

这是System.Data.SqlClient NuGet软件包的顶级目录结构:

enter image description here

观察包中如何为每个受支持的目标提供子目录(在本例中为MonoAndroid10,MonoTouch10,net46,net451,net461,netcoreapp2.1,netstandard1.2等)。软件包为每个目标提供了不同的程序集

  • 在面向.NET Framework 4.5.1,.NET Framework 4.6或.NET Framework 4.6.1时,分别来自net451net46net461目录的文件) 将会被使用。这些文件夹包含一个名为System.Data.SqlClient.dll的文件,其中不包含任何类。这是因为,当您以.NET Framework 4.x为目标时,System.Data.SqlClient内部的基类库已经提供了System.Data.dll(命名空间)类型,因此不需要任何其他类型。 (因此,如果仅针对.NET Framework 4.x构建,则根本不需要System.Data.SqlClient NuGet程序包。

    如果不相信我,以下是使用.NET Reflector工具(该工具可让您查看内部文件并反编译.NET程序集)的程序集文件内部的屏幕截图:

    enter image description here

  • 当通过.NET Standard定位其他平台时(即默认情况下不包括System.Data.dll,或者System.Data.dll不包括SqlClient时),NuGet软件包将请使用netstandard1.2netstandard1.3netstandard2.0目录,其中确实包含一个System.Data.SqlClient.dll,其中确实包含{{ 1}}命名空间以及您要使用的类型。这是该程序集的屏幕截图:

    enter image description here

  • 以及其他平台,例如System.Data.SqlClientMonoAndroidMonoTouchxamarinios等也具有自己的特定版本的汇编文件(或文件!)。

但是,即使您知道您的程序将仅在单个特定平台上运行,该平台上特定的NuGet程序包包含一个包含特定类型的程序集DLL-由于类型转发,它仍然是“错误的”:https://docs.microsoft.com/en-us/dotnet/framework/app-domains/type-forwarding-in-the-common-language-runtime < / p>

尽管类型转发意味着大多数引用某些程序集中类型的程序将继续正常运行,但不适用于基于反射的程序集加载和类型加载,这正是您的代码所要做的。考虑这种情况:

  • 推出了xamarintvos NuGet软件包的新版本,该软件包现在具有两个程序集:
    • System.Data.SqlClient(与以前相同,只是删除了System.Data.SqlClient.dll,但设置了引用SqlConnection的{​​{1}}属性)。
    • [TypeForwardedTo]System.Data.SqlClient.SqlConnection.dll类现在位于此程序集中)。
  • 您的代码现在将中断,因为它仅显式加载System.Data.SqlClient.SqlConnection.dll而不是SqlConnection并枚举这些类型。

这是龙...

现在,假设您已准备好不考虑所有建议,并且仍然编写假定特定程序集中存在特定类型的程序,那么该过程很简单:

System.Data.SqlClient.dll

答案 1 :(得分:0)

对于任何可能遇到相同问题的人,我都找到了解决方法

这是您以正确的方式加载正确的类型的方法

 var type = Type.GetType($"{typeName}, {assembly}");
 eg.
 var type =Type.GetType("System.Data.SqlClient.SqlConnection, System.Data.SqlClient");

这样,它应该动态加载dll。

答案 2 :(得分:-1)

我认为您必须提供指向LoadFrom(...)的完整路径。您应该知道应用程序的探测路径,因此只需将该路径连接到程序集的名称即可。除非对应用程序域进行一些麻烦,否则我认为从不位于探测路径的路径中加载是不费吹灰之力的。