Найкращий спосіб перевірити, чи є загальний тип рядком? (C #)


93

У мене є загальний клас, який повинен дозволяти будь-який тип, примітивний чи інший. Єдина проблема з цим - використання default(T). Коли ви викликаєте за замовчуванням тип значення або рядок, він ініціалізує його до розумного значення (наприклад, порожнього рядка). Коли ви викликаєте 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>();
    }
}

Але це відчуває себе як стукіт. Чи є більш приємний спосіб обробити рядок?

Відповіді:


161

Майте на увазі, що за замовчуванням (рядок) має значення null, а не рядок. Вам може знадобитися особливий випадок у вашому коді:

if (typeof(T) == typeof(String)) return (T)(object)String.Empty;

2
Я думав, що спробував це рішення раніше, і воно не спрацювало, але, мабуть, я зробив щось дурне. І дякуємо, що вказали за замовчуванням (рядок) повертає null, ми ще не стикалися з помилкою через це, але це правда.
Рекс М

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

2
А як щодо isключового слова? Чи не тут це корисно?
Naveed Butt

На даний момент неможливо застосувати оператор is з узагальненнями та присвоєнням чи прямим встановленням, чи не так?, Буде класною особливістю
Хуан Пабло Гарсія Коелло

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

Неперевірене, але перше, що спадало на думку.


4

Ви можете використовувати перерахування TypeCode . Викличте метод GetTypeCode для класів, що реалізують інтерфейс IConvertible, щоб отримати код типу для екземпляра цього класу. IConvertible реалізований Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char та String, тому ви можете перевірити наявність примітивних типів, використовуючи це. Докладніше про " Перевірку загального типу ".


2

Особисто мені подобається перевантаження методів:

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();
  }
}

0

Я знаю, що це запитання старе, але оновлення оновлено.

З 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


-6

Дискусія для 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>();
            } 
        } 

    }

3
Тестування на Stringім’я, особливо без відношення простору імен, є поганим. І мені теж не подобається, як ти конвертуєш.
CodesInChaos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.