Jika BaseFruit
memiliki konstruktor yang menerima int weight
, bisakah saya instantiate sepotong buah dengan metode generik seperti ini?
public void AddFruit<T>()where T: BaseFruit{
BaseFruit fruit = new T(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
Contoh ditambahkan di balik komentar. Sepertinya saya hanya dapat melakukan ini jika saya memberikan BaseFruit
konstruktor tanpa parameter dan kemudian mengisi semuanya melalui variabel anggota. Dalam kode asli saya (bukan tentang buah) ini agak tidak praktis.
-Perbaharui-
Jadi sepertinya itu tidak bisa diselesaikan dengan kendala dengan cara apa pun. Dari jawaban ada tiga solusi kandidat:
- Pola Pabrik
- Refleksi
- Penggerak
Saya cenderung berpikir refleksi adalah yang paling bersih, tetapi saya tidak bisa memutuskan di antara keduanya.
Jawaban:
Selain itu contoh yang lebih sederhana:
Perhatikan bahwa menggunakan batasan baru () pada T hanya untuk membuat pemeriksaan kompiler untuk konstruktor tanpa parameter publik pada waktu kompilasi, kode aktual yang digunakan untuk membuat tipe adalah kelas Activator.
Anda perlu memastikan diri Anda mengenai konstruktor spesifik yang ada, dan persyaratan semacam ini mungkin berupa bau kode (atau lebih tepatnya sesuatu yang harus Anda coba hindari dalam versi saat ini di c #).
sumber
new object[] { weight }
.CreateInstance
dideklarasikan dengan paramspublic static object CreateInstance(Type type, params object[] args)
,, jadi Anda bisa melakukannyareturn (T) Activator.CreateInstance(typeof(T), weight);
. Jika ada beberapa parameter, berikan sebagai argumen terpisah. Hanya jika Anda sudah memiliki parameter enumerable yang dibangun Anda harus repot mengubahnyaobject[]
dan meneruskannya keCreateInstance
.Func
yang menciptakan instance baru. MisalkanApple
penggunaan konstruktor adalahnew Apple(wgt)
. Kemudian tambahkan keApple
kelas definisi ini:static Func<float, Fruit> CreateOne { get; } = (wgt) => new Apple(wgt);
Di Factory definepublic static Fruit CreateFruitGiven(float weight, Func<float, Fruit> createOne) { return createOne(weight); }
Usage:Factory.CreateFruit(57.3f, Apple.CreateOne);
- yang membuat dan mengembalikanApple
, denganweight=57.3f
.Anda tidak dapat menggunakan konstruktor parameterised apa pun. Anda dapat menggunakan konstruktor tanpa parameter jika Anda memiliki
where T : new()
batasan " ".Ini menyebalkan, tapi begitulah hidup :(
Ini adalah salah satu hal yang ingin saya bahas dengan "antarmuka statis" . Anda kemudian dapat membatasi T untuk memasukkan metode statis, operator dan konstruktor, dan kemudian memanggil mereka.
sumber
Iya; ubah tempat Anda menjadi:
Namun, ini hanya berfungsi dengan konstruktor tanpa parameter . Anda harus memiliki cara lain untuk menyetel properti Anda (menyetel properti itu sendiri atau yang serupa).
sumber
Solusi paling sederhana
Activator.CreateInstance<T>()
sumber
Seperti yang ditunjukkan Jon, ini adalah masa pakai untuk membatasi konstruktor yang tidak memiliki parameter. Namun solusi yang berbeda adalah dengan menggunakan pola pabrik. Ini mudah dibatasi
Namun pilihan lain adalah menggunakan pendekatan fungsional. Lewati metode pabrik.
sumber
Anda dapat melakukannya dengan menggunakan refleksi:
EDIT: Menambahkan konstruktor == cek kosong.
EDIT: Varian yang lebih cepat menggunakan cache:
sumber
Sebagai tambahan untuk saran pengguna1471935:
Untuk membuat instance kelas generik dengan menggunakan konstruktor dengan satu atau lebih parameter, Anda sekarang dapat menggunakan kelas Activator.
Daftar objek adalah parameter yang ingin Anda berikan. Menurut Microsoft :
Ada juga versi generik dari CreateInstance (
CreateInstance<T>()
) tetapi yang satu itu juga tidak memungkinkan Anda untuk menyediakan parameter konstruktor.sumber
Saya membuat metode ini:
Saya menggunakannya dengan cara ini:
Kode:
sumber
Baru-baru ini saya menemukan masalah yang sangat mirip. Hanya ingin berbagi solusi kami dengan Anda semua. Saya ingin saya membuat contoh dari
Car<CarA>
menggunakan objek json yang memiliki enum:sumber
Itu masih mungkin, dengan kinerja tinggi, dengan melakukan hal berikut:
dan
Kelas-kelas yang relevan kemudian harus berasal dari antarmuka ini dan menginisialisasi sesuai. Harap dicatat, bahwa dalam kasus saya, kode ini adalah bagian dari kelas di sekitarnya, yang sudah memiliki <T> sebagai parameter generik. R, dalam kasus saya, juga adalah kelas read-only. IMO, ketersediaan publik dari fungsi Initialize () tidak memiliki efek negatif pada imutabilitas. Pengguna kelas ini bisa memasukkan objek lain, tetapi ini tidak akan mengubah koleksi yang mendasarinya.
sumber