У меня есть общий класс, который должен разрешать любой тип, примитивный или другой. Единственная проблема с этим - использование default(T). Когда вы вызываете default для типа значения или строки, он инициализирует его разумным значением (например, пустой строкой). Когда вы вызываете default(T) для объекта, он возвращает null. По разным причинам нам необходимо убедиться, что если это не примитивный тип, то у нас будет экземпляр типа по умолчанию, нет null. Вот попытка 1:
T createDefault()
{
if (typeof(T).IsValueType)
{
return default(T);
}
else
{
return Activator.CreateInstance<T>();
}
}
Проблема - строка не является типом значения, но у нее нет конструктора без параметров. Итак, текущее решение:
T createDefault()
{
if (typeof(T).IsValueType || typeof(T).FullName == "System.String")
{
return default(T);
}
else
{
return Activator.CreateInstance<T>();
}
}
Но это похоже на лачугу. Есть ли лучший способ справиться со строкой?





if (typeof(T).IsValueType || typeof(T) == typeof(String))
{
return default(T);
}
else
{
return Activator.CreateInstance<T>();
}
Не тестировал, но первое, что пришло в голову.
Имейте в виду, что по умолчанию (строка) имеет значение null, а не string.Empty. Вам может понадобиться особый случай в вашем коде:
if (typeof(T) == typeof(String)) return (T)(object)String.Empty;
@Matt Hamilton: +1, но вы должны обновить свой ответ, чтобы вернуть '(T) (object) String.Empty', как предлагает CodeInChaos, поскольку тип возвращаемого метода является общим, вы не можете просто вернуть строку.
А как насчет ключевого слова is? Разве это не пригодится здесь?
На данный момент невозможно применить оператор is с обобщениями и присваиванием или прямым экземпляром, не так ли? Это будет классная функция
Вы можете использовать перечисление ТипКод. Вызовите метод GetTypeCode для классов, реализующих интерфейс IConvertible, чтобы получить код типа для экземпляра этого класса. IConvertible реализуется с помощью Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char и String, поэтому вы можете проверять примитивные типы, используя это. Подробнее о "Проверка общего типа".
Обсуждение String здесь не работает.
У меня должен был быть следующий код для дженериков, чтобы он работал -
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>();
}
}
}
Тестировать String по имени, особенно без учета пространства имен, - это плохо. И мне тоже не нравится, как вы обращаетесь.
Лично мне нравится перегрузка методов:
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();
}
}
Я знаю, что это старый вопрос, но было обновление.
Начиная с C# 7.0, вы можете использовать оператор is для сравнения типов. Вам больше не требуется использование typeof, как в принятом ответе.
public bool IsObjectString(object obj)
{
return obj is string;
}
https://docs.microsoft.com/en-US/dotnet/csharp/language-reference/keywords/is
Я думал, что пробовал это решение раньше, и оно не сработало, но, должно быть, я сделал что-то глупое. И спасибо, что указали, что default (string) возвращает null, мы еще не столкнулись с ошибкой из-за этого, но это правда.