私はRequest.QueryString[]
変数を頻繁に使用します。
Page_load
では、次のようなことをよくします。
int id = -1;
if (Request.QueryString["id"] != null) {
try
{
id = int.Parse(Request.QueryString["id"]);
}
catch
{
// deal with it
}
}
DoSomethingSpectacularNow(id);
それはすべて少し不格好でゴミのようです。 Request.QueryString[]
sをどのように扱いますか?
以下は、次のようなコードを記述できる拡張メソッドです。
int id = request.QueryString.GetValue<int>("id");
DateTime date = request.QueryString.GetValue<DateTime>("date");
TypeDescriptor
を使用して変換を実行します。ニーズに基づいて、例外をスローする代わりにデフォルト値を取るオーバーロードを追加できます。
public static T GetValue<T>(this NameValueCollection collection, string key)
{
if(collection == null)
{
throw new ArgumentNullException("collection");
}
var value = collection[key];
if(value == null)
{
throw new ArgumentOutOfRangeException("key");
}
var converter = TypeDescriptor.GetConverter(typeof(T));
if(!converter.CanConvertFrom(typeof(string)))
{
throw new ArgumentException(String.Format("Cannot convert '{0}' to {1}", value, typeof(T)));
}
return (T) converter.ConvertFrom(value);
}
代わりにint.TryParseを使用して、try-catchブロックを取り除きます。
if (!int.TryParse(Request.QueryString["id"], out id))
{
// error case
}
この男を試してみてください...
List<string> keys = new List<string>(Request.QueryString.AllKeys);
その後、経由で本当に簡単に文字列を男を検索できるようになります...
keys.Contains("someKey")
私は少しヘルパーメソッドを使用しています:
public static int QueryString(string paramName, int defaultValue)
{
int value;
if (!int.TryParse(Request.QueryString[paramName], out value))
return defaultValue;
return value;
}
このメソッドを使用すると、次の方法でクエリ文字列から値を読み取ることができます。
int id = QueryString("id", 0);
まあ、代わりにint.TryParseを使用してください...
int id;
if (!int.TryParse(Request.QueryString["id"], out id))
{
id = -1;
}
もちろん、「存在しない」と「整数ではない」と同じ結果になるはずです。
編集:他のケースでは、とにかくリクエストパラメータを文字列として使用する場合、それらが存在することを検証することは間違いなく良い考えだと思います。
以下の拡張メソッドも使用して、このようにすることができます
int? id = Request["id"].ToInt();
if(id.HasValue)
{
}
//拡張メソッド
public static int? ToInt(this string input)
{
int val;
if (int.TryParse(input, out val))
return val;
return null;
}
public static DateTime? ToDate(this string input)
{
DateTime val;
if (DateTime.TryParse(input, out val))
return val;
return null;
}
public static decimal? ToDecimal(this string input)
{
decimal val;
if (decimal.TryParse(input, out val))
return val;
return null;
}
if(!string.IsNullOrEmpty(Request.QueryString["id"]))
{
//querystring contains id
}
私はそれぞれに関数を持っています(実際には、多くの静的な1つの小さなクラスです):
GetIntegerFromQuerystring(val)
GetIntegerFromPost(val)
....
失敗した場合は-1を返します(ほとんどの場合、私には問題ありません。負の数には他の関数もあります)。
Dim X as Integer = GetIntegerFromQuerystring("id")
If x = -1 Then Exit Sub
これはカルマリスクです...
DRYユニットテスト可能な抽象化があります。これは、クエリ文字列変数が多すぎて、従来の変換を維持できないためです。
以下のコードは、コンストラクターがNameValueCollection入力(this.source)を必要とするユーティリティクラスからのものであり、文字列配列「keys」は、レガシーアプリがかなり有機的であり、いくつかの異なる文字列が潜在的な入力キーになる可能性を開発したためです。しかし、拡張性が好きです。このメソッドは、キーのコレクションを検査し、必要なデータ型でそれを返します。
private T GetValue<T>(string[] keys)
{
return GetValue<T>(keys, default(T));
}
private T GetValue<T>(string[] keys, T vDefault)
{
T x = vDefault;
string v = null;
for (int i = 0; i < keys.Length && String.IsNullOrEmpty(v); i++)
{
v = this.source[keys[i]];
}
if (!String.IsNullOrEmpty(v))
{
try
{
x = (typeof(T).IsSubclassOf(typeof(Enum))) ? (T)Enum.Parse(typeof(T), v) : (T)Convert.ChangeType(v, typeof(T));
}
catch(Exception e)
{
//do whatever you want here
}
}
return x;
}
実際には、ジェネリックを使用してセッションを「ラップ」するユーティリティクラスがあり、これはすべての「うんざりする作業」を行いますが、QueryString値の処理についてもほぼ同じものがあります。
これにより、(多くの場合)チェックのためにコードの重複を削除できます。
例えば:
public class QueryString
{
static NameValueCollection QS
{
get
{
if (HttpContext.Current == null)
throw new ApplicationException("No HttpContext!");
return HttpContext.Current.Request.QueryString;
}
}
public static int Int(string key)
{
int i;
if (!int.TryParse(QS[key], out i))
i = -1; // Obviously Change as you see fit.
return i;
}
// ... Other types omitted.
}
// And to Use..
void Test()
{
int i = QueryString.Int("test");
}
注:
これは明らかに、テストコードに影響を与える可能性があるため、一部の人々が好まない静的を使用します。インスタンスおよび必要なインターフェイスに基づいて動作するものに簡単にリファクタリングできます。最軽量。
これが思考の糧となることを願っています。
ブライアンワッツの答えを修正して、質問のパラメータが存在せず、null許容型を指定した場合はnullを返すようにしました
public static T GetValue<T>(this NameValueCollection collection, string key)
{
if (collection == null)
{
return default(T);
}
var value = collection[key];
if (value == null)
{
return default(T);
}
var type = typeof(T);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = Nullable.GetUnderlyingType(type);
}
var converter = TypeDescriptor.GetConverter(type);
if (!converter.CanConvertTo(value.GetType()))
{
return default(T);
}
return (T)converter.ConvertTo(value, type);
}
これを行うことができます:
Request.QueryString.GetValue<int?>(paramName) ?? 10;