2016-11-23 5 views
0

У меня было несколько методов расширения, таких как ParseInt, ParseLong, ParseByte. теперь я пытаюсь сделать один метод расширения для всех из них. проблема заключается в том, что сделать Default опционный я должен дать ему значение, как T Default = 0, но он генерирует ошибку:Значение типа T по умолчанию

A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'T'

Если я использую его как T Default = (T)0 то я получаю другую ошибку:

Cannot convert type 'int' to 'T'

Это мой метод расширения:

public static T Parse<T>(this string x, T Default = 0) 
     { 
      Type type = typeof(T); 
      if(type == typeof(int)) 
      { if(!string.IsNullOrEmpty(x) int.TryParse(x , out Defualt); return Default; } 
     } 
+2

Не уверен, что можно увидеть точку между использованием 'Parse ' или 'ParseInt' в обоих случаях, когда вы должны быть« явным »относительно возвращаемого типа. – Sehnsucht

+0

@AshkanMobayenKhiabani: Некоторые советы вне темы. ** 1. ** Вместо 'typeof (T) == typeof (int)', вы можете просто сделать 'Default is int'. ** 2. ** Имена параметров обычно начинаются с небольшой буквы. Теперь 'default' уже является ключевым словом C#, но вы все равно можете вызвать свой параметр, выполнив его:' @ default'. Конечно, было бы лучше просто переименовать параметр в defaultValue. – stakx

ответ

5

Вы можете просто использовать default(T) вместо:

public static T Parse<T>(this string x, T defaultValue = default(T)) 

Однако, я бы сильно сомнению дизайн здесь - вы на самом деле не писать общий метод, но метод, который принимает одно из определенного набора типов и обрабатывает каждый из них по-разному. Бывают случаи, когда это навязывается вам, но у меня обычно есть Dictionary<T, SomeDelegate>, чтобы попытаться обработать его более чисто.

Кроме того, вы все еще будете иметь проблемы, требующие int.TryParse - вы не можете использовать параметр для Parse<T> в качестве аргумента - вам нужно что-то вроде:

if (typeof(T) == typeof(int)) 
{ 
    // You need to consider what you want to happen if 
    // int.TryParse returns false - do you want to return 0, 
    // or defaultValue? 
    int ret; 
    if (int.TryParse(x, out ret)) 
    { 
     // Annoying but required due to which conversions are available 
     return (T)(object) ret; 
    } 
} 
return defaultValue; 
+0

Большое спасибо. вы сделали свой день –

+0

Я не понял, что здесь используется в словаре. –

+0

@AshkanMobayenKhiabani: У вас будет делегат для каждой реализации, который вы можете искать по типу. Это позволяет избежать одного очень длинного метода. –

1

Как еще один ответ уже упоминалось , вы можете получить значение по умолчанию общего типа в качестве константы времени компиляции, используя ключевое слово default: default(T) в вашем случае.

  • Если T класса или тип интерфейса, default(T) является пустой ссылкой.
  • Если T - это структура, то default(T) - это значение, в котором все биты равны нулю. Это 0 для числовых типов, false для bool и сочетание обоих этих правил для пользовательских struct.

Но: Не делайте этого. Не создавайте этот общий метод, когда он будет работать только для нескольких выбранных типов. Как правило, общие методы предназначены для работы для всех типов. (Вы можете ограничить допустимые типы с родовыми связями параметров where T : …, но это не меняет основную идею.)

В вашем случае, общий метод только собирается работать на несколько типов, таких как int, long, float, double, decimal и т. Д. Вам даже нужно проверить эти типы в своем общем методе, чтобы вы могли отложить правильный метод (int.TryParse, double.TryParse и т. Д.). Это большой признак того, что ваш метод не должен быть общим.

Оставайтесь с предыдущими методами расширения ParseInt, ParseSingle, ParseDouble и т.д. Это был лучший дизайн.

Смежные вопросы