Dalam C # dapatkah saya melemparkan variabel tipe objek ke variabel tipe T di mana T didefinisikan dalam variabel Type?
c#
reflection
types
theringostarrs
sumber
sumber
Type
variabel, Anda bisa menggunakan refleksi untuk membuat turunan dari tipe itu. Dan kemudian Anda bisa menggunakan metode generik untuk mengembalikan tipe yang Anda inginkan dengan menyimpulkannya dari parameter jenis itu. Sayangnya, metode refleksi apa pun yang membuat turunan tipe akan memiliki tipe pengembalianobject
, sehinggaCastByExample
metode generik Anda juga akan digunakanobject
. Jadi benar-benar tidak ada cara untuk melakukan ini, dan bahkan jika ada, apa yang akan Anda lakukan dengan objek yang baru dilemparkan? Anda tidak dapat menggunakan metode atau apa pun karena Anda tidak tahu jenisnya.object
ataudynamic
. Jika Anda ingin memuat modul eksternal secara dinamis, Anda dapat meminta kelas berbagi antarmuka yang sama dan melemparkan objek ke sana. Jika Anda tidak mengontrol kode pihak ketiga, buat pembungkus kecil dan terapkan antarmuka itu.Jawaban:
Berikut adalah contoh pemeran dan orang yang insaf:
Edit:
Beberapa orang di komentar mengatakan bahwa jawaban ini tidak menjawab pertanyaan. Tapi jalurnya
(T) Convert.ChangeType(input, typeof(T))
menyediakan solusi. TheConvert.ChangeType
Metode mencoba untuk mengkonversi Obyek apapun untuk Type disediakan sebagai argumen kedua.Sebagai contoh:
Aku sudah menulis jawaban dengan obat generik, karena saya pikir itu adalah sangat mungkin menandatangani kode bau ketika Anda ingin cor
a something
untuka something else
tanpa penanganan jenis yang sebenarnya. Dengan antarmuka yang tepat yang seharusnya tidak perlu 99,9% dari waktu. Mungkin ada beberapa kasus tepi ketika datang ke refleksi bahwa itu mungkin masuk akal, tetapi saya akan merekomendasikan untuk menghindari kasus-kasus itu.Edit 2:
Beberapa tips tambahan:
object
ataudynamic
.sumber
T
seperti itu.Convert.ChangeType(input, typeof(T));
memberikan solusi. Anda dapat dengan mudah menggantitypeof(T)
dengan variabel tipe yang ada. Solusi yang lebih baik (jika mungkin) adalah untuk mencegah tipe dinamis secara bersamaan.T
yang tidak tersedia.T
tetapi Anda hanya mendapatkanobject
sebagai referensi. hmm, saya menemukan pertanyaan yang menarik dalam premis bahwa OP hanya memilikiType
variabel dan tidak ada info lainnya. Seolah-olah metode tanda tangan adalahConvert(object source, Type destination)
:) Namun saya mendapatkan poin AndaJawaban lain tidak menyebutkan tipe "dinamis". Jadi, untuk menambahkan satu jawaban lagi, Anda dapat menggunakan tipe "dinamis" untuk menyimpan objek yang dihasilkan tanpa harus membuang objek yang dikonversi dengan tipe statis.
Perlu diingat bahwa dengan menggunakan "dinamis" kompiler melewati pemeriksaan tipe statis yang dapat memperkenalkan kemungkinan kesalahan runtime jika Anda tidak hati-hati.
sumber
Berikut adalah metode saya untuk melemparkan objek tetapi tidak ke variabel tipe generik, bukan ke
System.Type
dinamis:Saya membuat ekspresi lambda pada saat run-time menggunakan
System.Linq.Expressions
, tipeFunc<object, object>
, yang membuka kotak inputnya, melakukan konversi tipe yang diinginkan kemudian memberikan hasilnya kotak. Yang baru diperlukan tidak hanya untuk semua jenis yang dicasting, tetapi juga untuk jenis yang dicasting (karena langkah unboxing). Menciptakan ekspresi ini sangat memakan waktu, karena refleksi, kompilasi dan metode dinamis yang dilakukan di bawah tenda. Untungnya sekali dibuat, ekspresi dapat dipanggil berulang kali dan tanpa overhead tinggi, jadi saya cache masing-masing.Perhatikan bahwa ini bukan sihir. Casting tidak terjadi dalam kode, seperti halnya dengan
dynamic
kata kunci, hanya data yang mendasari objek yang akan dikonversi. Pada waktu kompilasi kita masih harus bersusah payah mencari tahu dengan tepat apa jenis objek kita, membuat solusi ini tidak praktis. Saya menulis ini sebagai peretasan untuk memanggil operator konversi yang ditentukan oleh jenis arbitrer, tetapi mungkin seseorang di luar sana dapat menemukan use case yang lebih baik.sumber
using System.Linq.Expressions;
Type t = typeof(MyGeneric<>).MakeGenericType(obj.OutputType); var a = (t)Convert.ChangeType(obj, t); var b = (t)Caster.Cast(t, obj);
Type
. Anda tidak dapat melakukan casting menggunakan sintaks casting normal jika yang Anda miliki hanyalah objek Type. Jika Anda ingin dapat menggunakan objek sebagai beberapa tipe T pada waktu kompilasi, bukan runtime, Anda perlu melemparkannya menggunakan variabel tipe atau hanya nama tipe yang sebenarnya. Anda dapat melakukan yang pertama menggunakan jawaban Zaphrax.Mengesampingkan tinju dan unboxing untuk kesederhanaan, tidak ada tindakan runtime khusus yang terlibat dalam casting di sepanjang hierarki warisan. Ini sebagian besar waktu kompilasi. Pada dasarnya, seorang pemeran memberi tahu kompiler untuk memperlakukan nilai variabel sebagai tipe lain.
Apa yang bisa Anda lakukan setelah para pemain? Anda tidak tahu jenisnya, jadi Anda tidak akan dapat memanggil metode apa pun di dalamnya. Tidak akan ada hal khusus yang dapat Anda lakukan. Secara khusus, ini dapat berguna hanya jika Anda mengetahui jenis yang mungkin pada waktu kompilasi, melemparkannya secara manual dan menangani setiap kasus secara terpisah dengan
if
pernyataan:sumber
Bagaimana Anda bisa melakukan itu? Anda memerlukan variabel atau bidang tipe T di mana Anda dapat menyimpan objek setelah pemain, tetapi bagaimana Anda bisa memiliki variabel atau bidang tersebut jika Anda tahu T hanya saat runtime? Jadi, tidak, itu tidak mungkin.
sumber
CastTo
metodeObject
?Ketika datang untuk casting ke tipe Enum:
Dan Anda akan menyebutnya seperti itu:
Ini penting bagi saya jika mendapatkan nilai atribut Deskripsi beberapa tipe enum berdasarkan nilai int:
lalu:
Atau (pendekatan yang lebih baik), casting seperti itu bisa terlihat seperti itu:
sumber
Setelah tidak menemukan apa pun untuk berkeliling "Objek harus menerapkan IConvertible" pengecualian ketika menggunakan jawaban Zyphrax (kecuali untuk mengimplementasikan antarmuka). Saya mencoba sesuatu yang sedikit tidak konvensional dan bekerja untuk situasi saya.
Menggunakan paket nuget Newtonsoft.Json ...
sumber
Harm, masalahnya adalah Anda tidak memiliki T.
Anda hanya memiliki variabel Type.
Petunjuk ke MS, jika Anda bisa melakukan sesuatu seperti
TryCast<typeof(MyClass)>
jika mau menyelesaikan semua masalah kita.
sumber
Saya tidak akan pernah mengerti mengapa Anda perlu hingga 50 reputasi untuk meninggalkan komentar, tetapi saya hanya harus mengatakan bahwa jawaban @Curt persis seperti yang saya cari dan semoga orang lain.
Dalam contoh saya, saya memiliki ActionFilterAttribute yang saya gunakan untuk memperbarui nilai-nilai dokumen patch json. Saya tidak tahu apa model T untuk dokumen tambalan yang harus saya masukkan bersambung & deserialize ke dokumen JsonPatchDocument, modifikasi, lalu karena saya punya jenisnya, sambungkan & deserialisasi kembali ke jenis itu lagi.
sumber
sumber
lebih bersih:
sumber
Jika Anda perlu melemparkan objek saat runtime tanpa mengetahui tipe tujuan, Anda dapat menggunakan refleksi untuk membuat konverter dinamis.
Ini adalah versi yang disederhanakan (tanpa metode caching yang dihasilkan):
maka Anda dapat menyebutnya:
sumber