Próbuję połączyć kilka podobnych metod w metodę ogólną. Mam kilka metod, które zwracają wartość kwerendy lub null, jeśli ten obiekt kwerendy nie istnieje lub ma nieprawidłowy format. Byłoby to wystarczająco łatwe, gdyby wszystkie typy natywnie dopuszczały wartość null, ale muszę użyć typu ogólnego dopuszczającego wartość null dla liczb całkowitych i dat.
Oto, co mam teraz. Jednak przekaże z powrotem 0, jeśli wartość liczbowa jest nieprawidłowa i niestety jest to poprawna wartość w moich scenariuszach. Czy ktoś może mi pomóc? Dzięki!
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
niepowodzenia.Odpowiedzi:
Co się stanie, jeśli określisz wartość domyślną do zwrócenia, zamiast używać wartości domyślnej (T)?
public static T GetQueryString<T>(string key, T defaultValue) {...}
Ułatwia też dzwonienie:
var intValue = GetQueryString("intParm", Int32.MinValue); var strValue = GetQueryString("strParm", ""); var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified
Wadą jest to, że potrzebujesz magicznych wartości, aby oznaczyć nieprawidłowe / brakujące wartości zapytania.
źródło
long ? test
gdzie wartość domyślna powinna być pustaWiem, wiem, ale ...
public static bool TryGetQueryString<T>(string key, out T queryString)
źródło
Try
-Pattern powinny być dobrze znane każdej programista .NET. Nie jest źle, jeśli o mnie chodzi. W F # lub NET 4.0 użyłbyś opcji (lub wyboru)A co z tym? Zmień typ zwrotu z
T
naNullable<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; }
źródło
where T : struct
.string
jest tonullable
wartośćMożesz użyć czegoś w rodzaju może monady (chociaż wolałbym odpowiedź Jaya)
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; } }
Twoja metoda wyglądałaby następująco:
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>(); }
źródło
Convert.ChangeType()
nie obsługuje poprawnie typów dopuszczających wartość null lub wyliczeń w .NET 2.0 BCL (myślę, że jest to poprawione dla BCL 4.0). Zamiast komplikować zewnętrzną implementację, spraw, aby konwerter wykonywał więcej pracy za Ciebie. Oto implementacja, której używam: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); } }
Wtedy Twoja implementacja GetQueryString <T> może wyglądać następująco:
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; }
źródło
Lubię zaczynać od klasy takiej jak ta class settings {public int X {get; set;} public string Y {get; zestaw; } // powtórz w razie potrzeby
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 }
To działało dobrze w setkach projektów. Do analizowania wartości można użyć jednego z wielu innych rozwiązań do analizowania.
źródło