Saya mencoba untuk mencari tahu bagaimana Anda bisa pergi tentang mengimpor dan menggunakan .dll saat runtime di dalam aplikasi C #. Menggunakan Assembly.LoadFile () Saya telah berhasil membuat program saya memuat dll (bagian ini pasti berfungsi karena saya bisa mendapatkan nama kelas dengan ToString ()), namun saya tidak dapat menggunakan 'Output' metode dari dalam aplikasi konsol saya. Saya mengompilasi .dll kemudian memindahkannya ke proyek konsol saya. Apakah ada langkah ekstra antara CreateInstance dan kemudian dapat menggunakan metode?
Ini adalah kelas di DLL saya:
namespace DLL
{
using System;
public class Class1
{
public void Output(string s)
{
Console.WriteLine(s);
}
}
}
dan berikut adalah aplikasi yang ingin saya muat DLL
namespace ConsoleApplication1
{
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll");
foreach(Type type in DLL.GetExportedTypes())
{
var c = Activator.CreateInstance(type);
c.Output(@"Hello");
}
Console.ReadLine();
}
}
}
c#
reflection
dll
danbroooks
sumber
sumber
Jawaban:
Anggota harus dapat dipecahkan pada waktu kompilasi untuk dipanggil langsung dari C #. Jika tidak, Anda harus menggunakan objek refleksi atau dinamis.
Refleksi
namespace ConsoleApplication1 { using System; using System.Reflection; class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); foreach(Type type in DLL.GetExportedTypes()) { var c = Activator.CreateInstance(type); type.InvokeMember("Output", BindingFlags.InvokeMethod, null, c, new object[] {@"Hello"}); } Console.ReadLine(); } } }
Dinamis (.NET 4.0)
namespace ConsoleApplication1 { using System; using System.Reflection; class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); foreach(Type type in DLL.GetExportedTypes()) { dynamic c = Activator.CreateInstance(type); c.Output(@"Hello"); } Console.ReadLine(); } } }
sumber
Output
setiap jenis dalam rakitan, yang kemungkinan besar akan terlempar sebelum kelas "benar" ditemukan ...IDog dog = someInstance as IDog;
dan menguji apakah nilainya nol. Letakkan antarmuka Anda di DLL umum yang dibagikan oleh klien, dan plugin apa pun yang akan dimuat secara dinamis harus menerapkan antarmuka itu. Ini kemudian akan membiarkan Anda mengkodekan klien Anda terhadap antarmuka IDog dan memiliki intellisense + pemeriksaan tipe yang kuat pada waktu kompilasi daripada menggunakan dinamis.Class1
. Pada saat itu Anda bisa menggunakannew Class1()
. Penanya secara eksplisit menetapkan dependensi waktu proses.dynamic
memungkinkan program untuk tidak memerlukan ketergantungan waktu kompilasiClass1
sama sekali.Saat ini, Anda sedang membuat instance dari setiap jenis yang ditentukan di majelis . Anda hanya perlu membuat satu contoh
Class1
untuk memanggil metode ini:class Program { static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); var theType = DLL.GetType("DLL.Class1"); var c = Activator.CreateInstance(theType); var method = theType.GetMethod("Output"); method.Invoke(c, new object[]{@"Hello"}); Console.ReadLine(); } }
sumber
Anda perlu membuat instance dari tipe yang mengekspos
Output
metode:static void Main(string[] args) { var DLL = Assembly.LoadFile(@"C:\visual studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\DLL.dll"); var class1Type = DLL.GetType("DLL.Class1"); //Now you can use reflection or dynamic to call the method. I will show you the dynamic way dynamic c = Activator.CreateInstance(class1Type); c.Output(@"Hello"); Console.ReadLine(); }
sumber
Activator.CreateInstance()
mengembalikan sebuah objek, yang tidak memiliki metode Output.Sepertinya Anda berasal dari bahasa pemrograman dinamis? C # jelas bukan itu, dan apa yang Anda coba lakukan akan sulit.
Karena Anda memuat dll tertentu dari lokasi tertentu, mungkin Anda hanya ingin menambahkannya sebagai referensi untuk aplikasi konsol Anda?
Jika Anda benar-benar ingin memuat assembly melalui
Assembly.Load
, Anda harus melalui refleksi untuk memanggil anggota mana punc
Sesuatu seperti
type.GetMethod("Output").Invoke(c, null);
harus melakukannya.sumber
foreach (var f in Directory.GetFiles(".", "*.dll")) Assembly.LoadFrom(f);
Itu memuat semua DLL yang ada di folder yang dapat dieksekusi Anda.
Dalam kasus saya, saya mencoba menggunakan
Reflection
untuk menemukan semua subclass dari suatu kelas, bahkan di DLL lain. Ini berhasil, tetapi saya tidak yakin apakah itu cara terbaik untuk melakukannya.EDIT: Saya menghitung waktunya, dan sepertinya hanya memuatnya pertama kali.
Stopwatch stopwatch = new Stopwatch(); for (int i = 0; i < 4; i++) { stopwatch.Restart(); foreach (var f in Directory.GetFiles(".", "*.dll")) Assembly.LoadFrom(f); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); }
Keluaran: 34 0 0 0
Jadi seseorang berpotensi menjalankan kode itu sebelum pencarian Refleksi untuk berjaga-jaga.
sumber
Tidak terlalu sulit.
Anda dapat memeriksa fungsi yang tersedia dari objek yang dimuat, dan jika Anda menemukan fungsi yang Anda cari berdasarkan nama, maka mengintip fungsi yang diharapkan, jika ada. Jika itu panggilan yang Anda coba temukan, panggil itu menggunakan metode Invoke objek MethodInfo.
Pilihan lainnya adalah dengan membuat objek eksternal Anda ke sebuah antarmuka, dan mentransmisikan objek yang dimuat ke antarmuka itu. Jika berhasil, panggil fungsi secara native.
Ini hal yang sangat sederhana.
sumber