Mam klasę ogólną, która powinna zezwalać na dowolny typ, prymitywny lub inny. Jedynym problemem jest używanie default(T)
. Kiedy wywołujesz default dla typu wartości lub ciągu, inicjalizuje go do rozsądnej wartości (takiej jak pusty ciąg). Kiedy wywołujesz default(T)
obiekt, zwraca on null. Z różnych powodów musimy się upewnić, że jeśli nie jest to typ pierwotny, będziemy mieć domyślną instancję typu, a nie null. Oto próba 1:
T createDefault()
{
if(typeof(T).IsValueType)
{
return default(T);
}
else
{
return Activator.CreateInstance<T>();
}
}
Problem - łańcuch nie jest typem wartości, ale nie ma konstruktora bez parametrów. Tak więc obecne rozwiązanie to:
T createDefault()
{
if(typeof(T).IsValueType || typeof(T).FullName == "System.String")
{
return default(T);
}
else
{
return Activator.CreateInstance<T>();
}
}
Ale to wydaje się bzdurą. Czy jest lepszy sposób na obsłużenie obudowy sznurka?
is
słowem kluczowym? Czy to nie jest przydatne tutaj?if (typeof(T).IsValueType || typeof(T) == typeof(String)) { return default(T); } else { return Activator.CreateInstance<T>(); }
Niesprawdzone, ale pierwsza rzecz, jaka przyszła mi do głowy.
źródło
Możesz użyć wyliczenia TypeCode . Wywołaj metodę GetTypeCode w klasach, które implementują interfejs IConvertible, aby uzyskać kod typu dla wystąpienia tej klasy. IConvertible jest implementowana przez Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char i String, dzięki czemu można sprawdzić typy pierwotne przy użyciu tego. Więcej informacji na temat „ Generic Type Checking ”.
źródło
Osobiście lubię przeciążanie metod:
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(); } }
źródło
Wiem, że to pytanie jest stare, ale nastąpiła aktualizacja.
Od C # 7,0 można używać
is
operatora do porównywania typów. Nie musisz już używaćtypeof
tak, jak w zaakceptowanej odpowiedzi.public bool IsObjectString(object obj) { return obj is string; }
https://docs.microsoft.com/en-US/dotnet/csharp/language-reference/keywords/is
źródło
Dyskusja na temat String nie działa tutaj.
Musiałem mieć następujący kod dla generycznych, aby działał -
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>(); } } }
źródło
String
według nazwy, zwłaszcza bez uwzględnienia przestrzeni nazw, jest złe. Nie podoba mi się też sposób, w jaki się nawracasz.