Lagi

CodeDom.Compiler gagal di add-in Arcmap, tetapi berfungsi dari aplikasi konsol

CodeDom.Compiler gagal di add-in Arcmap, tetapi berfungsi dari aplikasi konsol


Metode Test dalam kode di bawah ini berhasil dalam aplikasi pengujian konsol, tetapi gagal ketika saya memanggilnya dari dalam add-in Arcmap, melemparkan ReflectionTypeLoadException dengan pengecualian loader yang mengatakan:

Tidak dapat memuat file atau rakitan 'KompilerLib, Versi=1.0.0.0, Culture=neutral, PublicKeyToken=null' atau salah satu dependensinya. Sistem tidak dapat menemukan berkas yang dicari.

KompilerLib adalah proyek perpustakaan kelas windows (3.5) dan ini adalah satu-satunya file dalam proyek (satu antarmuka dan satu kelas).

Apakah ada sesuatu yang khusus yang perlu saya lakukan jika saya menggunakan CodeDom.Compiler di dalam add-in?

menggunakan Sistem; menggunakan System.Collections.Generic; menggunakan System.Text; menggunakan System.CodeDom.Compiler; menggunakan System.Diagnostics; menggunakan System.IO; namespace KompilerLib { antarmuka publik IKalkulasi { string Test(); } public class Kompiler { private const string TYPENAME = "Kalk.Kalkulation"; Kompilasi IKalkulasi publik (bahasa string, Daftar referensi, sumber string) { Penyedia CodeDomProvider = CodeDomProvider.CreateProvider(bahasa); var parameter = new CompilerParameters(); parameter.GenerateInMemory = true; parameter.GenerateExecutable = false; foreach (referensi string dalam referensi) { parameter.ReferencedAssemblies.Add(reference); } var hasil = provider.CompileAssemblyFromSource(parameter, sumber); if (results.Errors == null || results.Errors.Count == 0) { Debug.Print(results.CompiledAssembly.ReflectionOnly.ToString()); foreach (Ketik t di hasil.CompiledAssembly.GetTypes()) Debug.Print(t.Name); var type = result.CompiledAssembly.GetType(TYPENAME); if (ketik == null) throw new Exception("type not found: " + TYPENAME); objek o = Activator.CreateInstance(type); if (o == null) throw new Exception("unable to createinstance"); var kalkulasi = o sebagai IKalkulasi; if (kalkulation == null) throw new Exception("tidak dapat melakukan cast ke IKalkulasi"); perhitungan kembali; } else { StringBuilder sb = new StringBuilder(); foreach (CompilerError err in results.Errors) sb.AppendLine(err.ErrorText); melempar Pengecualian baru(sb.ToString()); } } public static string Test() { var kompiler = new Kompiler(); var daftar = Daftar baru(); list.Add("Sistem.dll"); jalur string = kompiler.GetType().Assembly.Location; if (!File.Exists(path)) throw new Exception("file tidak ditemukan " + path); daftar.Tambahkan(jalur); sumber string = GetSource(); var kalk = kompiler.Kompile("CSharp", daftar, sumber); kembalikan kalk.Test(); } private static string GetSource() { StringBuilder sb = new StringBuilder(); sb.AppendLine("menggunakan KompilerLib; "); sb.AppendLine("namespace Kalk "); sb.AppendLine("{ "); sb.AppendLine("Kalkulasi kelas publik : IKalkulasi"); sb.AppendLine(" { "); sb.AppendLine("Tes string publik()"); sb.AppendLine(" { "); sb.AppendLine(" return "Halo Dunia"; "); sb.AppendLine(" } "); sb.AppendLine(" } "); sb.AppendLine("} "); kembali sb.ToString(); } } }

Memperbarui

Inilah perbaikannya menggunakan AssemblyResolve, terima kasih kepada blah238. Saya masih penasaran mengapa ini menjadi masalah di dalam arcmap.exe, tetapi tidak di dalam exe penguji konsol saya. Juga sepertinya Majelis yang paling mudah untuk diselesaikan adalah yang dijalankan oleh kompiler.

Kompilasi IKalkulasi publik (bahasa string, Daftar referensi, sumber string) { Penyedia CodeDomProvider = CodeDomProvider.CreateProvider(bahasa); var parameter = new CompilerParameters(); parameter.GenerateInMemory = true; parameter.GenerateExecutable = false; foreach (referensi string dalam referensi) { parameter.ReferencedAssemblies.Add(reference); } // ini benar-benar terlihat seperti peretasan… AppDomain.CurrentDomain.AssemblyResolve += (s,args) => { if (args.Name == this.GetType().Assembly.FullName) return this.GetType().Assembly ; lain kembali nol; }; var result = provider.CompileAssemblyFromSource(parameter, sumber); if (results.Errors == null || results.Errors.Count == 0) { var type = results.CompiledAssembly.GetType(TYPENAME); if (ketik == null) throw new Exception("type not found: " + TYPENAME); objek o = Activator.CreateInstance(type); if (o == null) throw new Exception("unable to createinstance"); var kalkulasi = o sebagai IKalkulasi; if (kalkulation == null) throw new Exception("tidak dapat melakukan cast ke IKalkulasi"); perhitungan kembali; } else { StringBuilder sb = new StringBuilder(); foreach (CompilerError err in results.Errors) sb.AppendLine(err.ErrorText); melempar Pengecualian baru(sb.ToString()); } }

Saya mengalami masalah serupa saat menggunakan .NET khususBagian Konfigurasi's dan saat menggunakan serialisasi biner (de). Masalah ini dibahas dalam komentar pertanyaan ini: Add-in ArcMap dengan app.settings tidak mengenali perubahan app.config?

Masalahnya tampaknya beberapa rakitan yang dirujuk oleh add-in tidak dapat diselesaikan dengan benar karena domain aplikasi add-in tidak terpisah dari domain aplikasi utama sehingga runtime .NET terlihat di jalur pemeriksaan perakitan aplikasi utama dan tidak menemukan mereka. Cara mengatasinya adalah dengan menggunakan Majelis.MuatDari dan menangani AppDomain.AssemblyResolve peristiwa.

Ini adalah perbaikan yang berhasil untuk saya dengan kebiasaanBagian Konfigurasimasalah. Saya harap ini berhasil dalam kasus Anda juga!


Tonton videonya: C# Source Generators - Write code that writes code - David Wengier