加载重命名的程序集并创建实例

时间:2014-05-28 13:24:07

标签: c# sqlite reflection .net-assembly invoke

我正在开发使用mixmode System.Data.SQLite.dll的软件。我需要在一个文件夹中提供其中的4个(x8​​6和x64用于.net 2.0和4.0)。这就是我将其重命名为

的原因
  

System.Data.SQLite.x64.dll

基于平台,我将加载其中一个并使用反射

创建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具有原始名称,我运行此代码没有问题。

assembly对象上调用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);

问题:为什么会发生这种情况?我该如何解决?

感谢。

2 个答案:

答案 0 :(得分:2)

出现此问题是因为您已重命名.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));

答案 1 :(得分:1)

您看到此行为的原因是您可能在编译后更改了dll的文件名。 DLL的原始文件名属性沿其编译存储在dll的元数据中。这就是为什么重命名dll而不是使用新名称重新编译它们并不是一个好主意。

为您的所有用例重新编译DLL 4次,问题就会消失。