Estoy tratando de combinar varios métodos similares en un método genérico. Tengo varios métodos que devuelven el valor de una cadena de consulta, o nulo si esa cadena de consulta no existe o no tiene el formato correcto. Esto sería bastante fácil si todos los tipos fueran anulables de forma nativa, pero tengo que usar el tipo genérico anulable para enteros y fechas.
Esto es lo que tengo ahora. Sin embargo, devolverá un 0 si un valor numérico no es válido y, lamentablemente, es un valor válido en mis escenarios. alguien me puede ayudar? ¡Gracias!
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;
}
ChangeType
falla.Respuestas:
¿Qué pasa si especificaste el valor predeterminado para devolver, en lugar de usar el valor predeterminado (T)?
public static T GetQueryString<T>(string key, T defaultValue) {...}
También facilita las llamadas:
var intValue = GetQueryString("intParm", Int32.MinValue); var strValue = GetQueryString("strParm", ""); var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified
La desventaja es que necesita valores mágicos para indicar valores de cadena de consulta no válidos / faltantes.
fuente
long ? test
donde el valor predeterminado debe ser nuloLo sé, lo sé, pero ...
public static bool TryGetQueryString<T>(string key, out T queryString)
fuente
Try
-pattern debe ser bien conocido por cualquier desarrollador de .NET. No es malo si me preguntas. En F # o NET 4.0, usaría Option (o Choice)¿Qué pasa con esto? Cambiar el tipo de retorno de
T
aNullable<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; }
fuente
where T : struct
.string
es unnullable
valorPuedes usar una especie de tal vez mónada (aunque prefiero la respuesta de 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; } }
Tu método se vería así:
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>(); }
fuente
Convert.ChangeType()
no maneja correctamente tipos o enumeraciones que aceptan valores NULL en .NET 2.0 BCL (aunque creo que está arreglado para BCL 4.0). En lugar de hacer la implementación externa más compleja, haga que el convertidor haga más trabajo por usted. Aquí hay una implementación que uso: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); } }
Entonces su implementación de GetQueryString <T> puede ser:
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; }
fuente
Me gusta comenzar con una clase como esta configuración de clase {public int X {get; set;} public string Y {get; conjunto; } // repetir según sea necesario
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 }
Esto ha funcionado bien en cientos de proyectos. Puede utilizar una de las muchas otras soluciones de análisis para analizar valores.
fuente