Cara terbaik untuk menguji apakah tipe generik adalah string? (C #)

95

Saya memiliki kelas generik yang harus mengizinkan semua jenis, primitif atau sebaliknya. Satu-satunya masalah dengan ini adalah menggunakan default(T). Ketika Anda memanggil default pada tipe nilai atau string, itu menginisialisasinya ke nilai yang wajar (seperti string kosong). Saat Anda memanggil default(T)suatu objek, ia mengembalikan null. Untuk berbagai alasan kita perlu memastikan bahwa jika ini bukan tipe primitif, maka kita akan memiliki contoh default dari tipe tersebut, bukan null. Ini percobaan 1:

T createDefault()
{
    if(typeof(T).IsValueType)
    {
        return default(T);
    }
    else
    {
        return Activator.CreateInstance<T>();
    }
}

Masalah - string bukanlah tipe nilai, tetapi tidak memiliki konstruktor tanpa parameter. Jadi, solusi saat ini adalah:

T createDefault()
{
    if(typeof(T).IsValueType || typeof(T).FullName == "System.String")
    {
        return default(T);
    }
    else
    {
        return Activator.CreateInstance<T>();
    }
}

Tapi ini terasa seperti lumpur. Apakah ada cara yang lebih baik untuk menangani kotak tali?

Rex M
sumber

Jawaban:

162

Perlu diingat bahwa default (string) adalah null, bukan string. Kosong. Anda mungkin menginginkan kasus khusus dalam kode Anda:

if (typeof(T) == typeof(String)) return (T)(object)String.Empty;
Matt Hamilton
sumber
2
Saya pikir saya mencoba solusi itu sebelumnya dan tidak berhasil, tetapi saya pasti telah melakukan sesuatu yang bodoh. Dan terima kasih telah menunjukkan default (string) mengembalikan nol, kami belum mengalami kesalahan karena itu, tetapi itu benar.
Rex M
1
@Matt Hamilton: +1, tetapi Anda harus memperbarui jawaban Anda untuk mengembalikan '(T) (object) String.Empty' seperti yang disarankan oleh CodeInChaos karena metode tipe pengembalian adalah generik, Anda tidak bisa hanya mengembalikan string.
VoodooChild
2
Bagaimana dengan iskata kuncinya? Bukankah itu berguna di sini?
Naveed Butt
Saat ini tidak memungkinkan untuk mengaplikasikan operator is dengan generics dan assignment atau direct instancing, bukan ?, akan menjadi fitur yang keren
Juan Pablo Garcia Coello
14
if (typeof(T).IsValueType || typeof(T) == typeof(String))
{
     return default(T);
}
else
{
     return Activator.CreateInstance<T>();
}

Belum teruji, tapi hal pertama yang terlintas dalam pikiran.

FlySwat
sumber
4

Anda dapat menggunakan enumerasi TypeCode . Panggil metode GetTypeCode di kelas yang menerapkan antarmuka IConvertible untuk mendapatkan kode jenis untuk instance kelas tersebut. IConvertible diimplementasikan oleh Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char, dan String, sehingga Anda dapat memeriksa tipe primitif menggunakan ini. Info lebih lanjut tentang " Pemeriksaan Jenis Generik ".

jfs
sumber
2

Secara pribadi, saya suka metode overloading:

public static class Extensions { 
  public static String Blank(this String me) {      
    return String.Empty;
  }
  public static T Blank<T>(this T me) {      
    var tot = typeof(T);
    return tot.IsValueType
      ? default(T)
      : (T)Activator.CreateInstance(tot)
      ;
  }
}
class Program {
  static void Main(string[] args) {
    Object o = null;
    String s = null;
    int i = 6;
    Console.WriteLine(o.Blank()); //"System.Object"
    Console.WriteLine(s.Blank()); //""
    Console.WriteLine(i.Blank()); //"0"
    Console.ReadKey();
  }
}
theoski
sumber
-6

Diskusi untuk String tidak berfungsi di sini.

Saya harus memiliki kode berikut untuk obat generik agar berfungsi -

   private T createDefault()
    { 

        {     
            if(typeof(T).IsValueType)     
            {         
                return default(T);     
            }
            else if (typeof(T).Name == "String")
            {
                return (T)Convert.ChangeType(String.Empty,typeof(T));
            }
            else
            {
                return Activator.CreateInstance<T>();
            } 
        } 

    }
Anil
sumber
3
Menguji Stringberdasarkan nama, terutama tanpa memperhatikan namespace itu buruk. Dan saya juga tidak suka cara Anda pindah agama.
CodesInChaos