2010-01-27 2 views
57

Я пытаюсь объединить кучу подобных методов в общий метод. У меня есть несколько методов, которые возвращают значение querystring, или null, если эта последовательность не существует или не находится в правильном формате. Это было бы достаточно легко, если бы все типы были обнуляемы, но я должен использовать тип с нулевым общим типом для целых чисел и дат.Создание общего метода в C#

Вот что у меня есть сейчас. Однако он вернет 0, если числовое значение недействительно и, к сожалению, является допустимым значением в моих сценариях. Может кто-нибудь мне помочь? Благодаря!

public static T GetQueryString<T>(string key) where T : IConvertible 
{ 
    T result = default(T); 

    if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false) 
    { 
     string value = HttpContext.Current.Request.QueryString[key]; 

     try 
     { 
      result = (T)Convert.ChangeType(value, typeof(T)); 
     } 
     catch 
     { 
      //Could not convert. Pass back default value... 
      result = default(T); 
     } 
    } 

    return result; 
} 
+0

Не совсем уверен, как это относится к этой ситуации ... ?? –

+0

Он переносит кучу реализаций, поэтому звоните по старой функции, запомните результат, вызовите новую функциональность, запомните результат, сравните. Теперь сделайте это 100 раз с кучей случайных входов и вуаля! –

+0

Прошу прощения, я до сих пор не понимаю, как это применимо в этом случае. Я все еще пытаюсь заставить функцию работать. –

ответ

41

Что делать, если вы указали значение по умолчанию для возвращения, вместо использования значения по умолчанию (T)?

public static T GetQueryString<T>(string key, T defaultValue) {...} 

Это делает его легче вызов тоже:

var intValue = GetQueryString("intParm", Int32.MinValue); 
var strValue = GetQueryString("strParm", ""); 
var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified 

Недостаток является вам нужны магические значения для обозначения недопустимых/отсутствующих значений строки запроса.

+0

Да, это кажется более жизнеспособным, чем полагаться на значение по умолчанию целого числа. Я буду помнить об этом. Я все еще надеюсь, что моя оригинальная функция будет работать на всех типах, хотя я просто могу прибегнуть к использованию не общих функций. –

+0

Почему бы просто не вернуть что-то отличное от нуля за недопустимое целое число? Вы можете вернуть все, что хотите, это не действительное значение или уже имеет особую цель, например null. Вы даже можете создать свой собственный тип InvalidInteger или что-то еще. Вы возвращаете значение null для плохого запроса, не так ли? Вы также можете вернуть это значение для недопустимого целого числа, поэтому значение null будет означать просто «что-то плохое, и у меня нет никакой ценности для вас», и, может быть, передать причину кода по ссылке на эту функцию? –

+1

Как получить значение для: 'long? test', где значение по умолчанию должно быть нулевым – Arshad

8

Что относительно этого? Измените тип возвращаемого T к Nullable<T>

public static Nullable<T> GetQueryString<T>(string key) where T : struct, IConvertible 
     { 
      T result = default(T); 

      if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false) 
      { 
       string value = HttpContext.Current.Request.QueryString[key]; 

       try 
       { 
        result = (T)Convert.ChangeType(value, typeof(T)); 
       } 
       catch 
       { 
        //Could not convert. Pass back default value... 
        result = default(T); 
       } 
      } 

      return result; 
     } 
+0

Ошибка: тип «T» должен быть невообразимым типом значения, чтобы использовать его как параметр «T» в родовом типе или методе «System.Nullable ». –

+0

Вам также нужно указать 'where T: struct'. – Aaronaught

+0

Такая же ошибка ..... –

11

Я знаю, я знаю, но ...

public static bool TryGetQueryString<T>(string key, out T queryString) 
+3

Шаблон 'Try' должен быть хорошо известен любому разработчику .NET. Это не плохо, если вы спросите меня. В F # или NET 4.0 вы должны использовать опцию (или выбор) –

+6

Если по какой-либо другой причине я стараюсь избегать этого, потому что мне не нравится «предварительно объявлять» эту выходную переменную, особенно если ее даже никогда не используют - отходы от того, что в противном случае могло бы быть отличной строкой кода. – Jay

+0

На самом деле это самый простой способ решить вашу проблему - определить одну функцию, например, выше + два помощника, которые будут использовать эту функцию (это будет 4 лайнера). – greenoldman

2

Convert.ChangeType() не правильно обрабатывать NULLABLE типы или перечислений в .NET 2.0 BCL (я думаю, он исправлен для BCL 4.0, хотя). Вместо того, чтобы сделать внешнюю реализацию более сложной, сделайте конвертер больше для вас. Вот реализация я использую:

public static class Converter 
{ 
    public static T ConvertTo<T>(object value) 
    { 
    return ConvertTo(value, default(T)); 
    } 

    public static T ConvertTo<T>(object value, T defaultValue) 
    { 
    if (value == DBNull.Value) 
    { 
     return defaultValue; 
    } 
    return (T) ChangeType(value, typeof(T)); 
    } 

    public static object ChangeType(object value, Type conversionType) 
    { 
    if (conversionType == null) 
    { 
     throw new ArgumentNullException("conversionType"); 
    } 

    // if it's not a nullable type, just pass through the parameters to Convert.ChangeType 
    if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 
    { 
     // null input returns null output regardless of base type 
     if (value == null) 
     { 
     return null; 
     } 

     // it's a nullable type, and not null, which means it can be converted to its underlying type, 
     // so overwrite the passed-in conversion type with this underlying type 
     conversionType = Nullable.GetUnderlyingType(conversionType); 
    } 
    else if (conversionType.IsEnum) 
    { 
     // strings require Parse method 
     if (value is string) 
     { 
     return Enum.Parse(conversionType, (string) value);   
     } 
     // primitive types can be instantiated using ToObject 
     else if (value is int || value is uint || value is short || value is ushort || 
      value is byte || value is sbyte || value is long || value is ulong) 
     { 
     return Enum.ToObject(conversionType, value); 
     } 
     else 
     { 
     throw new ArgumentException(String.Format("Value cannot be converted to {0} - current type is " + 
           "not supported for enum conversions.", conversionType.FullName)); 
     } 
    } 

    return Convert.ChangeType(value, conversionType); 
    } 
}

Тогда ваша реализация GetQueryString < T> может быть:

public static T GetQueryString<T>(string key) 
{ 
    T result = default(T); 
    string value = HttpContext.Current.Request.QueryString[key]; 

    if (!String.IsNullOrEmpty(value)) 
    { 
     try 
     { 
      result = Converter.ConvertTo<T>(value); 
     } 
     catch 
     { 
      //Could not convert. Pass back default value... 
      result = default(T); 
     } 
    } 

    return result; 
}
0

Я хотел бы начать с классом, как этого настройки класса { общественности INT X { get; set;} public string Y {get; задавать; } // повторять по мере необходимости

public settings() 
{ 
    this.X = defaultForX; 
    this.Y = defaultForY; 
    // repeat ... 
} 
public void Parse(Uri uri) 
{ 
    // parse values from query string. 
    // if you need to distinguish from default vs. specified, add an appropriate property 

} 

Это хорошо работало на 100 проектов. Вы можете использовать один из многих других решений синтаксического анализа для анализа значений.

2

Вы можете использовать своего рода Может монады (хотя я бы предпочел ответ Джея)

public class Maybe<T> 
{ 
    private readonly T _value; 

    public Maybe(T value) 
    { 
     _value = value; 
     IsNothing = false; 
    } 

    public Maybe() 
    { 
     IsNothing = true; 
    } 

    public bool IsNothing { get; private set; } 

    public T Value 
    { 
     get 
     { 
      if (IsNothing) 
      { 
       throw new InvalidOperationException("Value doesn't exist"); 
      } 
      return _value; 
     } 
    } 

    public override bool Equals(object other) 
    { 
     if (IsNothing) 
     { 
      return (other == null); 
     } 
     if (other == null) 
     { 
      return false; 
     } 
     return _value.Equals(other); 
    } 

    public override int GetHashCode() 
    { 
     if (IsNothing) 
     { 
      return 0; 
     } 
     return _value.GetHashCode(); 
    } 

    public override string ToString() 
    { 
     if (IsNothing) 
     { 
      return ""; 
     } 
     return _value.ToString(); 
    } 

    public static implicit operator Maybe<T>(T value) 
    { 
     return new Maybe<T>(value); 
    } 

    public static explicit operator T(Maybe<T> value) 
    { 
     return value.Value; 
    } 
} 

Ваш метод будет выглядеть следующим образом:

public static Maybe<T> GetQueryString<T>(string key) where T : IConvertible 
    { 
     if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false) 
     { 
      string value = HttpContext.Current.Request.QueryString[key]; 

      try 
      { 
       return (T)Convert.ChangeType(value, typeof(T)); 
      } 
      catch 
      { 
       //Could not convert. Pass back default value... 
       return new Maybe<T>(); 
      } 
     } 

     return new Maybe<T>(); 
    } 
Смежные вопросы