Лучший способ проверить, является ли универсальный тип строкой? (C#)

У меня есть общий класс, который должен разрешать любой тип, примитивный или другой. Единственная проблема с этим - использование 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>();
    }
}

Но это похоже на лачугу. Есть ли лучший способ справиться со строкой?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
97
0
89 950
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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;

Я думал, что пробовал это решение раньше, и оно не сработало, но, должно быть, я сделал что-то глупое. И спасибо, что указали, что default (string) возвращает null, мы еще не столкнулись с ошибкой из-за этого, но это правда.

Rex M 29.05.2010 04:32

@Matt Hamilton: +1, но вы должны обновить свой ответ, чтобы вернуть '(T) (object) String.Empty', как предлагает CodeInChaos, поскольку тип возвращаемого метода является общим, вы не можете просто вернуть строку.

VoodooChild 23.01.2012 21:04

А как насчет ключевого слова is? Разве это не пригодится здесь?

Naveed Butt 15.09.2014 11:21

На данный момент невозможно применить оператор is с обобщениями и присваиванием или прямым экземпляром, не так ли? Это будет классная функция

Juan Pablo Garcia Coello 18.01.2017 10:05

Вы можете использовать перечисление ТипКод. Вызовите метод 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 по имени, особенно без учета пространства имен, - это плохо. И мне тоже не нравится, как вы обращаетесь.

CodesInChaos 13.02.2011 15:30

Лично мне нравится перегрузка методов:

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

Другие вопросы по теме