C # Buat T Baru ()

159

Anda dapat melihat apa yang saya coba (tetapi gagal) lakukan dengan kode berikut:

protected T GetObject()
{
    return new T();
}

Bantuan apa pun akan sangat dihargai.

EDIT:

Konteksnya adalah sebagai berikut. Saya bermain-main dengan kelas pengontrol khusus untuk berasal dari semua pengontrol, dengan metode standar. Jadi dalam konteksnya, saya perlu membuat instance objek tipe controller yang baru. Jadi pada saat penulisan, itu seperti:

public class GenericController<T> : Controller
{
    ...

    protected T GetObject()
    {
        return (T)Activator.CreateInstance(ObjectType);
    }        

    public ActionResult Create()
    {
        var obj = GetObject()

        return View(obj);
    }

Jadi saya putuskan refleksi paling mudah di sini. Saya setuju bahwa, tentu saja memberikan pernyataan awal dari pertanyaan, jawaban yang paling tepat untuk menandai sebagai benar adalah yang menggunakan kendala () baru. Saya sudah memperbaikinya.

Hanshan
sumber
27
Tidak, saya tidak melihat apa yang Anda coba dan gagal lakukan. Saya melihat sepotong kode yang bisa menjadi bagian dari program kerja, tanpa konteks, tanpa pesan kesalahan, dan tanpa penjelasan.
Ben Voigt
17
Ah, aku benci kalau jawaban yang salah dipilih!
David Heffernan

Jawaban:

409

Lihatlah Kendala baru

public class MyClass<T> where T : new()
{
    protected T GetObject()
    {
        return new T();
    }
}

Tbisa berupa kelas yang tidak memiliki konstruktor default: dalam hal ini new T()akan menjadi pernyataan yang tidak valid. The new()kendala mengatakan bahwa Tharus memiliki konstruktor default, yang membuat new T()hukum.

Anda dapat menerapkan batasan yang sama untuk metode generik:

public static T GetObject<T>() where T : new()
{
    return new T();
}

Jika Anda harus melewati parameter:

protected T GetObject(params object[] args)
{
    return (T)Activator.CreateInstance(typeof(T), args);
}
Alex Aza
sumber
2
Terima kasih, sobat - Saya senang telah mempelajari ini hari ini. Mengingat konteks metode saya, saya mencari solusi refleksi. Bersulang!
Hanshan
8
@nulliusinverba - hmm ... alangkah baiknya jika Anda menunjukkan konteks metode Anda dalam pertanyaan.
Alex Aza
1
@nulliusinverba - Anda tidak menunjukkan dalam pertanyaan bahwa Anda memerlukan parameter.
Alex Aza
1
@Alex - Ketika saya membaca pertanyaannya, saya berasumsi dia tidak ingin parameter: S Pilih suara untuk Anda :)
Phill
Apakah mungkin menggunakan sesuatu seperti batasan (parameter) baru?
Louis Rhys
29

Cara lain adalah dengan menggunakan refleksi:

protected T GetObject<T>(Type[] signature, object[] args)
{
    return (T)typeof(T).GetConstructor(signature).Invoke(args);
}
Sean Thoman
sumber
Terima kasih, sobat - Saya menggunakan solusi ini mengingat konteks metode ini.
Hanshan
22
Sama seperti FYI, ini bisa juga ditulis sebagai Activator.CreateInstance (typeof (T), signature, args); lihat msdn.microsoft.com/en-us/library/4b0ww1we.aspx untuk detail lebih lanjut.
Chris Baxter
@Calgary Coder: Apa gunanya tanda tangan tipe [], Anda bisa langsung memanggil CreateInstance dengan params, tanpa secara eksplisit menentukan tanda tangan. Dalam kedua kasus Anda akan mendapatkan MissingMethodException jika konstruktor yang cocok tidak ada.
Boris B.
4
Bahkan jika ini adalah jawaban yang paling cocok untuk Anda, itu jelas bukan yang terbaik untuk komunitas. Orang-orang yang mencari pertanyaan ini mencari jawaban dari bawah, sungguh.
Perangkap
Dan apa sebenarnya konteks itu? Harap tambahkan ke pertanyaan awal.
James
18

Hanya untuk penyelesaian, solusi terbaik di sini adalah sering membutuhkan argumen fungsi pabrik:

T GetObject<T>(Func<T> factory)
{  return factory(); }

dan menyebutnya sesuatu seperti ini:

string s = GetObject(() => "result");

Anda dapat menggunakannya untuk meminta atau memanfaatkan parameter yang tersedia, jika perlu.

Joel Coehoorn
sumber
16

The kendala baru baik-baik saja, tapi jika Anda membutuhkan T menjadi jenis nilai juga, gunakan ini:

protected T GetObject() {
    if (typeof(T).IsValueType || typeof(T) == typeof(string)) {
        return default(T);
    } else {
       return (T)Activator.CreateInstance(typeof(T));
    }
}
Lukas Cenovsky
sumber
7

Karena ini ditandai C # 4. Dengan kerangka kerja open source, ImpromptuIntereface akan menggunakan dlr untuk memanggil konstruktor, ini secara signifikan lebih cepat daripada Activator ketika konstruktor Anda memiliki argumen, dan secara lambat lebih lambat ketika tidak. Namun keuntungan utama adalah bahwa ia akan menangani konstruktor dengan parameter opsional C # 4.0 dengan benar, sesuatu yang tidak akan dilakukan Activator.

protected T GetObject(params object[] args)
{
    return (T)Impromptu.InvokeConstructor(typeof(T), args);
}
jbtule
sumber
4

Untuk mendapatkan ini saya mencoba kode berikut:

  protected T GetObject<T>()
    {
        T obj = default(T);
        obj =Activator.CreateInstance<T>();
        return obj ;
    }
UJS
sumber