Создание общего метода в С#
Я пытаюсь объединить кучу подобных методов в общий метод. У меня есть несколько методов, которые возвращают значение querystring, или null, если эта последовательность не существует или не находится в правильном формате. Это было бы достаточно легко, если бы все типы были обнуляемыми изначально, но я должен использовать тип с нулевым общим типом для целых чисел и дат.
Вот что у меня сейчас. Однако он вернет 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;
}
Ответы
Ответ 1
Что делать, если вы указали значение по умолчанию для возврата вместо использования значения по умолчанию (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 date if not specified
Недостатком является то, что вам нужны магические значения для обозначения недопустимых/отсутствующих значений запроса.
Ответ 2
Я знаю, я знаю, но...
public static bool TryGetQueryString<T>(string key, out T queryString)
Ответ 3
Как насчет этого? Измените тип возврата с 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;
}
Ответ 4
Convert.ChangeType()
корректно обрабатывает типы NULL или перечисления в .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 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 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;
}
Ответ 5
Вы можете использовать вид Модификации Maybe (хотя я бы предпочел ответить Jay)
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>();
}
Ответ 6
Мне нравится начинать с такого класса настройки класса { public int X {get; set;} открытая строка 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 проектах. Вы можете использовать одно из многих других решений синтаксического анализа для анализа значений.