Buat instance kelas dari string

217

Apakah ada cara untuk membuat instance kelas berdasarkan fakta saya tahu nama kelas saat runtime. Pada dasarnya saya akan memiliki nama kelas dalam sebuah string.

PeteT
sumber
Anda tampaknya telah menggambarkan solusi yang ingin Anda terapkan, tetapi bukan masalah yang Anda coba selesaikan. Mungkin Anda mencoba melakukan sesuatu dengan ekstensibilitas, dalam hal ini saya sarankan Anda memeriksa Kerangka Kerja Ekstensibilitas yang Dikelola .
Jay Bazuzi

Jawaban:

159

Lihatlah metode Activator.CreateInstance .

Matt Hamilton
sumber
15
Terkait dengan contoh-contoh hebat: stackoverflow.com/questions/493490/…
John S.
Juga posting ini akan relevan juga, karena jenis Anda perlu ditemukan: stackoverflow.com/questions/1825147/…
Brad Parks
4
Misalnya:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono
2
Catatan penting di sini: .Unwrap () untuk melewati pegangan remoting sehingga Anda benar-benar dapat melakukan gips. @ Endy - Terima kasih
Roger Willcocks
77

Cukup sederhana. Asumsikan bahwa nama kelas Anda Cardan namespace adalah Vehicles, lalu kirimkan parameter Vehicles.Caryang mengembalikan objek bertipe Car. Seperti ini, Anda dapat membuat instance kelas apa pun secara dinamis.

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

Jika Nama Sepenuhnya Berkualitas Anda (yaitu, Vehicles.Cardalam hal ini) di majelis lain, itu Type.GetTypeakan menjadi nol. Dalam kasus seperti itu, Anda memiliki perulangan melalui semua majelis dan menemukan Type. Untuk itu Anda bisa menggunakan kode di bawah ini

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Sekarang jika Anda ingin memanggil konstruktor berparameter lakukan yang berikut ini

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

dari pada

Activator.CreateInstance(t);
Sarath Avanavu
sumber
Bagaimana cara menggunakannya tanpa casting dan bagaimana melakukan cast dari string yang diberikan ??
TaW
1
@ Ta - untuk menggunakan instance kelas, Anda harus memiliki pengetahuan tentang apa yang akan dilakukan - jika tidak, Anda tidak akan dapat menggunakannya. Kasus penggunaan yang paling umum untuk ini adalah casting ke beberapa antarmuka yang memberi Anda kontrak yang telah ditentukan. (Ini berlaku kecuali Anda menggunakan dynamickode - lihat stackoverflow.com/a/2690661/904521 )
Tomer Cagan
1
Jangan mengkodekan jenis variabel dalam nama itu, misalnya:. Tidak perlu untuk awalan strFullyQualifiedNamedengan str, fullyQualifiedNameakan melakukan pekerjaan.
Mehdi Dehghani
Kata kunci strdigunakan sebagai bagian dari konvensi penamaan untuk variabel. Organisasi dan proyek tertentu bersikeras untuk mengikuti ini, maka saya gunakan. Jika Anda akan bekerja di oraganisasi / proyek tertentu, Anda akan tahu ini. Seperti yang Anda katakan tanpa strjuga itu akan melakukan pekerjaan :) @MehdiDehghani
Sarath Avanavu
1
Saya tahu, tidak perlu bekerja di organisasi mana pun untuk mengetahui tentang konvensi penamaan, meskipun konvensi ini dikenal sebagai notasi Hongaria dan itu salah satu konvensi penamaan yang buruk dan usang di luar sana. khusus untuk C #
Mehdi Dehghani
55

Saya berhasil menggunakan metode ini:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

Anda harus melemparkan objek yang dikembalikan ke jenis objek yang Anda inginkan.

Ray Li
sumber
9
Saya mencoba membayangkan sebuah skenario di mana membuat objek melalui nama kelas dan kemudian melemparkannya sebagai jenis yang masuk akal sama sekali.
MusiGenesis
13
Saya mengerti apa yang kamu maksud. Tampaknya berlebihan. Jika Anda tahu nama kelasnya, mengapa Anda membutuhkan string dinamis? Satu situasi mungkin adalah casting Anda ke kelas dasar dan string mewakili keturunan kelas dasar itu.
Ray Li
4
Jika kelas dasar diketahui, Anda bisa menggunakan kelas dasar atau antarmuka sebagai argumen untuk meneruskan turunan tanpa refleksi.
Garet Claborn
3
Skenario yang berguna: Anda hanya perlu antarmuka serialisasi, atau antarmuka lain yang cukup umum. Anda tidak akan melemparkannya ke kelas, tetapi setidaknya untuk sesuatu yang lebih dari objek
Harald Coppoolse
2
Bagaimana melakukan pemeran dari string yang diberikan ??
TaW
23

Mungkin pertanyaan saya seharusnya lebih spesifik. Saya benar-benar tahu kelas dasar untuk string sehingga diselesaikan dengan:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

Kelas Activator.CreateInstance memiliki berbagai metode untuk mencapai hal yang sama dengan cara yang berbeda. Saya bisa saja melemparkannya ke objek tetapi di atas adalah yang paling berguna untuk situasi saya.

PeteT
sumber
4
Alih-alih merespons di bagian pertanyaan, saya sarankan Anda mengedit pertanyaan Anda dan perhatikan perubahannya. Anda akan mendapatkan lebih banyak / jawaban yang lebih baik untuk melakukannya.
Jason Jackson
Terima kasih telah memposting baris kode tertentu yang sesuai untuk Anda. Memilah-milah semua CreateInstance berlebihan dan berbagai cara untuk menghasilkan Jenis butuh banyak waktu, yang Anda menyelamatkan saya.
Ethel Evans
4

Saya tahu saya terlambat ke permainan ... tetapi solusi yang Anda cari mungkin kombinasi di atas, dan menggunakan antarmuka untuk menentukan objek Anda aspek yang dapat diakses publik.

Kemudian, jika semua kelas Anda yang akan dihasilkan dengan cara ini mengimplementasikan antarmuka itu, Anda bisa menggunakan tipe antarmuka dan bekerja dengan objek yang dihasilkan.

Denny
sumber
4

Untuk membuat instance kelas dari proyek lain dalam solusi, Anda bisa mendapatkan majelis yang ditunjukkan dengan nama kelas apa pun (misalnya BaseEntity) dan membuat instance baru:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");
asd
sumber
3

Misalnya, jika Anda menyimpan nilai berbagai jenis dalam bidang basis data (disimpan sebagai string) dan memiliki bidang lain dengan nama jenis (yaitu, String, bool, int, MyClass), maka dari data bidang itu, Anda dapat, mungkin, buat kelas jenis apa pun menggunakan kode di atas, dan isi dengan nilai dari bidang pertama. Ini tentu saja tergantung pada jenis yang Anda simpan memiliki metode untuk mengurai string ke jenis yang benar. Saya telah menggunakan ini berkali-kali untuk menyimpan pengaturan preferensi pengguna dalam database.

Greg Osborne
sumber
-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

kenapa kamu mau menulis kode seperti ini? Jika Anda memiliki kelas 'ReportClass' tersedia, Anda dapat instantiate langsung seperti yang ditunjukkan di bawah ini.

ReportClass report = new ReportClass();

Kode ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));digunakan ketika Anda tidak memiliki kelas yang diperlukan tersedia, tetapi Anda ingin membuat instance dan atau atau memanggil metode secara dinamis.

Maksud saya ini berguna ketika Anda mengetahui perakitan tetapi saat menulis kode Anda tidak memiliki kelas yang ReportClasstersedia.

Asish
sumber