Exception:
Could not load file or assembly 'DllFileName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5cadd04e079758c3' or one of its dependencies. The system cannot find the file specified.
最近在研究動態讀取非當前EXE目錄的DLL文件的方法。
Reflection, Activator.CreateInstance,或者AppDomain啥的。
當只讀取單個Dll的時候沒啥問題,但是當這個Dll以來和它同一個文件夾的dll時,就會報錯。
搜了很久,終於搜到篇靠譜的文章。
http://theraneman.blogspot.com/2010/04/creating-instance-of-type-outside.html
文章是2010年的,10年過去了,呵呵。。。
大致解決方法代碼如下,直接COPY過來留個念,慢慢啃。
1. 一般操作,會導致報錯
Assembly assembly = Assembly.LoadFrom(C:\Sample\Sample.dll); Type appType = assembly.GetType(MyType); object objClassInstance = Activator.CreateInstance(appType);
2. 解決方案一
有點過的方案,哈哈,
使用這個方法,不能直接實例化你需要的函數,而必須實例化一個繼承了MarshalByRefObject的函數,
入下面代碼中的SampleProxy
Assembly assembly = Assembly.LoadFrom(@"C:\Sample\Sample.dll"); AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = @"C:\Sample\"; AppDomain appDomain = AppDomain.CreateDomain("AppHostDomain", null, setup); object obj = appDomain.CreateInstanceFromAndUnwrap(@"C:\Sample\Sample.dll", "SampleProxy");
3.解決方案二
被原作者成為冗余啰嗦的方案,不過在我看來挺好的。
該方案將循環遞歸加載所依賴的DLL
Assembly assembly = Assembly.LoadFrom(@"C:\Sample\Sample.dll");
AssemblyName[] arr = assembly.GetReferencedAssemblies(); LoadAssembly(arr); private void LoadAssembly(AssemblyName[] arr) { Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); List<string> names = new List<string>(); foreach (Assembly assem in loadedAssemblies) { names.Add(assem.FullName); } foreach (AssemblyName aname in arr) { if (!names.Contains(aname.FullName)) { try { Assembly loadedAssembly = Assembly.LoadFrom(@"C:\Sample\" + aname.Name + ".dll"); AssemblyName[] referencedAssemblies = loadedAssembly.GetReferencedAssemblies(); LoadAssembly(referencedAssemblies); } catch (Exception ex) { continue; } } } }
3. 解決方案三
定於當前AppDomain的一個事件,就是當需要哪個Assembly而又找不到時,就會觸發。
Assembly assembly = Assembly.LoadFrom(@"C:\Sample\Sample.dll"); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); object obj = Activator.CreateInstanceFrom(@"C:\Sample\Sample.dll", "MyType"); Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { string path = @"C:\Sample\Sample.dll"; string test = path.Substring(0,path.LastIndexOf(@"\")); string[] arr = args.Name.Split(','); string assemblyName = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"; string newPath = System.IO.Path.Combine(test, assemblyName); return Assembly.LoadFrom(newPath); }