[英]How to convert [TYPE] to nullable<[TYPE]> in C#?
Question: 题:
I wrote a method to retrieve a SQL result as a list of a class instead of a datatable. 我编写了一个方法来检索SQL结果作为类的列表而不是数据表。 The problem is, I have a int field in the database, which is nullable.
问题是,我在数据库中有一个可以为空的int字段。
If I hit a row with a NULL
int
, DataReader
returns DbNull.Value
instead of null. 如果我用
NULL
int
命中一行, DataReader
将返回DbNull.Value
而不是null。 So System.Convert.ChangeType(objVal, fi.FieldType)
throws an exception, because it can't convert DbNull
to an int
. 所以
System.Convert.ChangeType(objVal, fi.FieldType)
抛出异常,因为它无法将DbNull
转换为int
。
So far so bad. 到目前为止这么糟糕。 I thought I had solved the problem, when I just compared
objVal
to DbNull.Value
and if true, did this instead: System.Convert.ChangeType(null, fi.FieldType)
我以为我已经解决了这个问题,当我只是将
objVal
与objVal
进行DbNull.Value
,如果是,则执行此操作: System.Convert.ChangeType(null, fi.FieldType)
unfortunately, I just realized, the resulting integer type is 0 instead of NULL. 不幸的是,我刚刚意识到,结果整数类型是0而不是NULL。
So I just tried changing the int type in my class to Nullable<int>
, but now I have the problem that when a value is not DbNull.Value
, ChangeType
throws an exception because it can't convert int
to nullable<int>
... 所以我只是尝试将我的类中的int类型更改为
Nullable<int>
,但现在我遇到的问题是,当值不是DbNull.Value
, ChangeType
会抛出异常,因为它无法将int
转换为nullable<int>
。 ..
So now I try to detect the type of the object returned by datareader
, and convert it to a nullable value. 所以现在我尝试检测
datareader
返回的对象的类型,并将其转换为可空值。
tTypeForNullable
is correctly shown as Nullable<int>
. tTypeForNullable
正确显示为Nullable<int>
。 But when I look at the result type, I get: int
. 但是当我查看结果类型时,我得到:
int
。
Why is that ? 这是为什么 ? And more important: How can I do that properly ?
更重要的是:我该如何正确地做到这一点?
Please note that because type is an object, I can't use a generic method to create Nullable<int>
. 请注意,因为type是一个对象,所以我不能使用泛型方法来创建
Nullable<int>
。
bool bisnull = IsNullable(objVal);
bool bisnullt = IsNullable(fi.FieldType);
if (bisnullt)
{
Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());
//object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
//object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
object result = Activator.CreateInstance(tTypeForNullable, objVal);
Type tres = result.GetType();
fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
}
Here's the complete routine for reference: 这是完整的例行程序供参考:
public virtual System.Collections.Generic.IList<T> GetList<T>(System.Data.IDbCommand cmd)
{
System.Collections.Generic.List<T> lsReturnValue = new System.Collections.Generic.List<T>();
T tThisValue = default(T);
Type t = typeof(T);
lock (cmd)
{
using (System.Data.IDataReader idr = ExecuteReader(cmd))
{
lock (idr)
{
while (idr.Read())
{
//idr.GetOrdinal("")
tThisValue = Activator.CreateInstance<T>();
// Console.WriteLine(idr.FieldCount);
for (int i = 0; i < idr.FieldCount; ++i)
{
string strName = idr.GetName(i);
object objVal = idr.GetValue(i);
System.Reflection.FieldInfo fi = t.GetField(strName);
//Type tttttt = fi.FieldType;
if (fi != null)
{
//fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
if (objVal == System.DBNull.Value)
{
objVal = null;
fi.SetValue(tThisValue, null);
}
else
{
//System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(fi.FieldType);
bool bisnull = IsNullable(objVal);
bool bisnullt = IsNullable(fi.FieldType);
if (bisnullt)
{
Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());
//object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
//object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
object result = Activator.CreateInstance(tTypeForNullable, objVal);
Type tres = result.GetType();
fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
}
fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
}
}
else
{
System.Reflection.PropertyInfo pi = t.GetProperty(strName);
if (pi != null)
{
//pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);
if (objVal == System.DBNull.Value)
{
objVal = null;
pi.SetValue(tThisValue, null, null);
}
else
{
pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);
}
}
// Else silently ignore value
} // End else of if (fi != null)
//Console.WriteLine(strName);
} // Next i
lsReturnValue.Add(tThisValue);
} // Whend
idr.Close();
} // End Lock idr
} // End Using idr
} // End lock cmd
return lsReturnValue;
} // End Function GetList
with this: 有了这个:
public System.Data.IDataReader ExecuteReader(System.Data.IDbCommand cmd)
{
System.Data.IDataReader idr = null;
lock(cmd)
{
System.Data.IDbConnection idbc = GetConnection();
cmd.Connection = idbc;
if (cmd.Connection.State != System.Data.ConnectionState.Open)
cmd.Connection.Open();
idr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
} // End Lock cmd
return idr;
} // End Function ExecuteReader
Please note that because type is an object, I can't use a generic method to create Nullable<int>
. 请注意,因为type是一个对象,所以我不能使用泛型方法来创建
Nullable<int>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.