トップ回答者
SqlDbTypeからの.NET Framework 型の取得

質問
-
お世話になります。
ADO.NETでパラメーター(SqlParameter)を作成時にSqlDbTypeと値(Value)を
指定しますが、このパラメーターから値を取得しようと考えます。下記参考ページのこの部分→Int32 categoryID = (Int32) command.Parameters["@Identity"].Value;
参考ページhttp://msdn.microsoft.com/ja-jp/library/3btz0xwf.aspx
// Assumes connection is a valid SqlConnection.
SqlCommand command = new SqlCommand("InsertCategory" , connection);
command.CommandType = CommandType.StoredProcedure;SqlParameter parameter = command.Parameters.Add(
"@RowCount", SqlDbType.Int);
parameter.Direction = ParameterDirection.ReturnValue;parameter = command.Parameters.Add(
"@CategoryName", SqlDbType.NChar, 15);parameter = command.Parameters.Add("@Identity", SqlDbType.Int);
parameter.Direction = ParameterDirection.Output;command.Parameters["@CategoryName"].Value = "New Category";
command.ExecuteNonQuery();Int32 categoryID = (Int32) command.Parameters["@Identity"].Value;
Int32 rowCount = (Int32) command.Parameters["@RowCount"].Value;
その際、型を動的に取得する方法はありますでしょうか?
この方法は(Int32)と記述しておりますが汎用的に、どうにか出来ないか?と考えます。下記ページに対比表がありますが
http://msdn.microsoft.com/ja-jp/library/yy6y35y8.aspx
SqlDbTypeがNVarCharなら対比する.NET Framework 型のsystem.stringを取得したいのです。良い方法などありましたら、ご教示よろしくお願いいたします。
回答
すべての返信
-
AriAriビスカス さんからの引用 Int32 categoryID = (Int32) command.Parameters["@Identity"].Value;
Int32 rowCount = (Int32) command.Parameters["@RowCount"].Value;
その際、型を動的に取得する方法はありますでしょうか?
この方法は(Int32)と記述しておりますが汎用的に、どうにか出来ないか?と考えます。下記ページに対比表がありますが
http://msdn.microsoft.com/ja-jp/library/yy6y35y8.aspx
SqlDbTypeがNVarCharなら対比する.NET Framework 型のsystem.stringを取得したいのです。良い方法などありましたら、ご教示よろしくお願いいたします。
何か矛盾しているような気がしますが・・・
何故なら、右辺と左辺の型を一致させるわけですが、プログラマが左辺(これは動的に
変わらない)を Int32 rowCount と書くということは、右辺には (Int32) と書くしかあり得
ないわけで、汎用的にどうにかできる必要はないと思いますけど。
ただし、左辺が String 型で、右辺が色々変わる場合は、以下のようにするということも
あると思います。
Code Snippetprotected string GetStringFromReader(SqlDataReader reader)
{
string text = String.Empty;
for (int i = 0; i < reader.FieldCount; i++)
{
object obj = reader[i];
if (obj is DBNull)
{
text += "DBNull, ";
}
else if (obj == null)
{
text += "null, ";
}
else if (obj is Int32)
{
text += "Int32: " + ((Int32)obj).ToString() + ", ";
}
else if (obj is String)
{
text += "String: " + (string)obj + ", ";
}
else if (obj is DateTime)
{
text += "DateTime: " + ((DateTime)obj).ToShortDateString() + ", ";
}
else if (obj is Decimal)
{
text += "Decimal: " + ((decimal)obj).ToString() + ", ";
}
else
{
text += "Unknown, ";
}
}
text.TrimEnd(new char[] { ',', ' ' });
text += "<br />";
return text;}
-
AriAriビスカス さんからの引用 その際、型を動的に取得する方法はありますでしょうか?
この方法は(Int32)と記述しておりますが汎用的に、どうにか出来ないか?と考えます。どのようにしたいのかがよく見えません。
実際に書くとコンパイルエラーになるコードでも良いので、イメージを示して頂けませんか?
現時点の情報だけだと、私も矛盾を感じます。
単純にキャストを書きたくないと言っても、やはりどこかでその値を特定の型とみなして処理するはずなので、動的に取得したい理由が見えません。
Code Snippetobject o = null; // 本来は何かの値。例えばValueプロパティの戻り値など。
string s = GetValue<string>(o); // この位置で何型で欲しいか静的に決まっている。
static T GetValue<T>(object o)
{
if (o == null) return default(T);
if (o is T) return (T)o;
throw new InvalidCastException();
}単純にType型が欲しいのであれば、GetTypeメソッドでできますけれど。
同じ理屈でToStringメソッドもobject型で実装されているので、何らかの値か型の名前を得ることができます。
-
SurferOnWwwさん
Azuleanさん回答ありがとうございます。
漠然としたイメージになってしまいますが、
command.Parameters["@Identity"].Valueを一旦、hashtableなどに保管(add)しておいて
必要になった時に取り出せないか?と言うのが最終的にやりたいことです。<イメージ>
private struct sqlBindStruct
{
public SqlDbType serverType;
public object dbValues;
}//登録
sqlBindStruct bs1 = new sqlBindStruct();
sqlBindStruct bs2 = new sqlBindStruct();bs1.serverType = SqlDbType.Int;
bs1.dbValues = command.Parameters["@Identity"].Value;bs2.serverType = SqlDbType.NChar;
bs2.dbValues = command.Parameters["@CategoryName"].Value;Hashtable ht = new Hashtable();
ht.Add("Identity",bs1);
ht.Add("CategoryName",bs2);//取り出し
??? bindData= (???)((sqlBindStruct)(ht["Identity"])).dbValues;
1.構造体sqlBindStructを用意しておき、"SqlDbType"と"値"をセット
2.これをhashtableへ登録
3.取り出し時に適正なキャストし取り出すこの取り出しの際SqlDbTypeより、.NET Framework 型を取得しキャスト(???部)
上記の場合はstring型の@CategoryNameとint型の@Identityが混在してaddされているイメージです。
指摘いただいた左辺の型(これは動的に変わらない)も、合わせてうまく
記述できれば?と考えますが、やっぱり無理ですかね・・・>単純にType型が欲しいのであれば、GetTypeメソッドでできますけれど。
Azuleanさん。このことでしょうか?command.Parameters["@Identity"].Value.GetType() -
AriAriビスカス さんからの引用 指摘いただいた左辺の型(これは動的に変わらない)も、合わせてうまく
記述できれば?と考えますが、やっぱり無理ですかね・・・この左辺の型に代入する部分はいずれにせよ、キャストが必要です。
.NET Framework 2.0以降であればHashTableクラスの代わりにDictionaryクラスを使えば、キャストの回数を1回減らせますが、基本的に AAA aaa = (AAA)dictionary["Identity"].dbValue; といったように、型を2回書く必要があるのは変わりません。
キャストを書く回数を減らすだけなら、下記のような書き方もできます。
Code Snippetprivate struct TestStore
{
public object data;
}
private void Test()
{
TestStore test = new TestStore();
test.data = 12;
int aaa;
GetValue(test, out aaa); // aaa = 12string bbb;
GetValue(test, out bbb); // bbb = null
}private void GetValue<T>(TestStore source, out T output)
{
if (source.data != null && source.data is T)
{
output = (T)source.data;
}
else
{
output = default(T);
}
}※戻り値の型が違うだけの場合、型の推論を行ってくれないため、GetValue<int>みたいな書き方が必要になります。それを避けるためにoutキーワードで引数にしています。
AriAriビスカス さんからの引用 >単純にType型が欲しいのであれば、GetTypeメソッドでできますけれど。
Azuleanさん。このことでしょうか?command.Parameters["@Identity"].Value.GetType()そうですが、今回の用途には使えません。
-
AriAriビスカス さんからの引用 1.構造体sqlBindStructを用意しておき、"SqlDbType"と"値"をセット
2.これをhashtableへ登録
3.取り出し時に適正なキャストし取り出すこの取り出しの際SqlDbTypeより、.NET Framework 型を取得しキャスト(???部)
上記の場合はstring型の@CategoryNameとint型の@Identityが混在してaddされているイメージです。個人的な意見としては、手間が多いのに、その手間をかけるだけのメリットがほと
んど無いように思えます。
イメージをお持ちなら、一度実際にサンプルを作るなどして、検討してみてはいか
がでしょう?
そのイメージと普通(?)にキャストすることのメリット/デメリットを比較して、メリット
があるか否かご自分で判断してみてください。