C# 加载重命名的程序集并创建实例
我正在开发使用mixmode System.Data.SQLite.dll的软件。我需要在一个文件夹中交付其中4个(针对.net 2.0和4.0的x86和x64)。这就是为什么我把它改名为 System.Data.SQLite.x64.dll 基于平台,我将加载其中一个,并使用反射创建C# 加载重命名的程序集并创建实例,c#,sqlite,reflection,.net-assembly,invoke,C#,Sqlite,Reflection,.net Assembly,Invoke,我正在开发使用mixmode System.Data.SQLite.dll的软件。我需要在一个文件夹中交付其中4个(针对.net 2.0和4.0的x86和x64)。这就是为什么我把它改名为 System.Data.SQLite.x64.dll 基于平台,我将加载其中一个,并使用反射创建SQLiteConnection var assembly = Assembly.LoadFile(@"d:\sqlite-netFx20-binary-bundle-x64-2005-1.0.92.0\Syste
SQLiteConnection
var assembly = Assembly.LoadFile(@"d:\sqlite-netFx20-binary-bundle-x64-2005-1.0.92.0\System.Data.SQLite.x64.dll");
Type t = assembly.GetExportedTypes()[8];
object sqliteCon = Activator.CreateInstance(t, @"Data Source=d:\nwind.db;Version=3;");
最后一行抛出一个异常
类型的未处理异常
mscorlib.dll中出现“System.Reflection.TargetInvocationException”
无法加载DLL“System.Data.SQLite.DLL”:指定的模块
找不到。(来自HRESULT的异常:0x8007007E)
我没有在项目中引用SQLite.dll。
如果dll有它的原始名称,我运行这段代码没有问题
在程序集
对象上调用CreateInstance并从类型中获取构造函数并调用它会引发相同的异常:
//ConstructorInfo ctor = t.GetConstructor(new[] { typeof(string) });
//object instance = ctor.Invoke(@"Data Source=d:\nwind.db;Version=3;");
//object ass = assembly.CreateInstance("System.Data.SQLite.SQLiteConnection", false, BindingFlags.CreateInstance, null, new object[] { @"Data Source=d:\nwind.db;Version=3;" }, null, null);
问题:为什么会发生这种情况,我如何解决
谢谢。出现此问题是因为您已重命名.DLL。除非您想更改mete数据中的某些变量,否则必须以某种方式重命名库 我以前遇到过这个问题,这是我使用的解决方案:
string tempFile = string.Format("{0}\\{1}", System.IO.Path.GetTempPath(), "System.Data.SQLite.dll");
System.IO.File.WriteAllBytes(tempFile, System.IO.File.ReadAllBytes(@"C:\System.Data.SQLite_x64.dll"));
var assembly = Assembly.LoadFile(tempFile);
Type t = assembly.GetExportedTypes()[8];
object sqliteCon = Activator.CreateInstance(t, @"Data Source=d:\nwind.db;Version=3;");
它会将文件的副本创建到您计算机上的临时目录中,并将其重命名回原始名称
在关闭应用程序时,不要忘记删除文件
--编辑:
我上面使用的方法并不适合您的项目,因为您只需确定一次所需的库。因此,我会在程序第一次加载时重命名正确的库,这样您就不必在用户每次启动程序时创建临时文件:
string myPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
string originalName = "System.Data.SQLite.dll";
// If we haven't already renamed the right library
if (!System.IO.File.Exists(string.Format("{0}\\{1}", myPath, originalName)))
{
foreach (var file in System.IO.Directory.GetFiles(myPath))
{
string fileName = System.IO.Path.GetFileName(file);
if (fileName.StartsWith("System.Data.SQLite."))
{
// !! Do your platform checks here !!
// ..
// Copy the file with its original name
System.IO.File.Move(file, file.Replace(fileName, "System.Data.SQLite.dll"));
// Delete old file (not necessary)
System.IO.File.Delete(file);
}
}
}
var assembly = Assembly.LoadFile(string.Format("{0}\\{1}", myPath, originalName));
您看到这种行为的原因是,您可能正在编译dll后更改其文件名。DLL的原始文件名属性存储在DLL编译过程中的元数据中。这就是为什么重命名DLL并不是一个好主意,而是使用新名称重新编译它们
为所有用例重新编译DLL 4次,问题就会消失。IMHO创建一个安装程序,为系统提供合适的DLL,而不是将4个DLL全部发送并重命名,这会更简单。@DStanley不在我的情况下,因为我的软件是软件开发人员的类库,所以我必须提供所有DLL+1 I喜欢你的编辑,但我忘了提到,我的软件是一个面向开发人员的类库。开发人员可能会在其项目中引用其中一个DLL,该项目也使用我的库,因此文件重命名不是我最喜欢的解决方案。谢谢。我理解,在你的情况下,你不会同意文件重命名。您可以在程序集中循环其引用的库,并检查其中一个引用是否是您的库,如果不是,您可以始终将自己的库放在磁盘上(或者,如果已经存在,请重命名它)。我刚刚尝试过这样做,但仍然得到相同的异常。现在我真的不知道为什么。如果你有空余时间,可以试试吗。我只留下了SQLite.Interop.2013、SQLite.Interop.Static.2013、System.Data.SQLite.2013和System.Data.SQLite.Module.2013。我在SQLite.Interop.Static.2013中修改了目标名称,现在dll有了新名称。Thanks@VladL真奇怪。因为任何地方都不应该提及旧名称。除非有一个DLL本身。不幸的是,我现在无法做到这一点。但我建议您使用Fuslogvw.exe转储Fusion活动(dll解析)。它将帮助您查看哪个模块正在尝试加载该DLL,以及在何处查找该DLL。