C# DataRow.Field<;T>;(字符串列)引发无效的强制转换异常

C# DataRow.Field<;T>;(字符串列)引发无效的强制转换异常,c#,datarow,C#,Datarow,你好 IDEVisual Studio 2010 .NET3.5 平台WinForms 所谓“问题”是指 我有一个数据库表,其列[ID]INT-IDENTITY(1,1)主键不为NULL。当查询这个表并将值存储在局部变量中时,我得到一个无效的强制转换异常;示例代码: string sQuery = @" SELECT [ID], [Description] FROM [Sources] ORDER BY [Description] "; using (DataTable

你好

IDEVisual Studio 2010
.NET3.5
平台WinForms

所谓“问题”是指

我有一个数据库表,其列
[ID]INT-IDENTITY(1,1)主键不为NULL
。当查询这个表并将值存储在局部变量中时,我得到一个无效的强制转换异常;示例代码:

string sQuery = @"
    SELECT [ID], [Description]
    FROM [Sources]
    ORDER BY [Description] ";

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{
    foreach (DataRow drSource in dtSources.Rows)
    {
        int iID = drSource.Field<int>("ID"); // InvalidCastException
        string sDescrption = drSource.Field<string>("Description");
    }
}
string sQuery=@”
选择[ID],[Description]
来自[来源]
按[说明]订购“;
使用(DataTable dtSources=SQLHelper.Fetch(sQuery))
{
foreach(dtSources.Rows中的DataRow drSource)
{
int iID=drSource.Field(“ID”);//InvalidCastException
字符串sDescrption=drSource.Field(“说明”);
}
}

当逐步执行并对故障线路执行“快速观察”时,我发现,通过将线路更改为
drSource.Field(“ID”)
,单元格值类型为
short
,而不是
int
。在表定义中,这显然是且
int
,为什么会发生这种情况?此外,
short
应该隐式转换为
int
,因为
short
更小,应该“适合”正确吗?

出于好奇,如果您自己从键/值集合显式强制转换它,会发生什么

int iID = (int)drSource["ID"];

根据字段扩展的实现,您的字段具有DbNull值

public static T Field<T>(this DataRow row, string columnName)
    {
        DataSetUtil.CheckArgumentNull<DataRow>(row, "row");
        return UnboxT<T>.Unbox(row[columnName]);
    }
公共静态T字段(此数据行,字符串列名)
{
DataSetUtil.CheckArgumentNull(行,“行”);
返回Unbox.Unbox(行[列名称]);
}
UnboxT是一个私有类,提供将对象转换为T的方法。在您的情况下,使用ValueField转换器:

private static class UnboxT<T>
{
    internal static readonly Converter<object, T> Unbox;

    static UnboxT()
    {
       DataRowExtensions.UnboxT<T>.Unbox =  
          new Converter<object, T>(DataRowExtensions.UnboxT<T>.ValueField);
    }

    private static T ValueField(object value)
    {
        if (DBNull.Value == value)
        {
            // You get this exception 
            throw DataSetUtil.InvalidCast(Strings.DataSetLinq_NonNullableCast(typeof(T).ToString()));
        }
        return (T) value;
    }
}
私有静态类unbox
{
内部静态只读转换器;
静态取消文本()
{
DataRowExtensions.Unbox.Unbox=
新转换器(DataRowExtensions.unText.ValueField);
}
私有静态T值字段(对象值)
{
if(DBNull.Value==Value)
{
//你得到这个例外
抛出DataSetUtil.InvalidCast(Strings.DataSetLinq_NonNullableCast(typeof(T).ToString());
}
返回(T)值;
}
}

如果您的列是一个可为空的int,但您正试图分配一个int,默认值为0:

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{ 
    foreach (DataRow drSource in dtSources.Rows)'
    { 
        int iID = drSource.Field<int?>("ID") ?? 0; 
        string sDescrption = drSource.Field<string>("Description"); 
    }
}
使用(DataTable dtSources=SQLHelper.Fetch(sQuery))
{ 
foreach(数据源中的数据行drSource.Rows)'
{ 
int iID=drSource.Field(“ID”)??0;
字符串sDescrption=drSource.Field(“说明”);
}
}

如果您的列是可为null的int,并且您希望分配给可为null的int:

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{
    foreach (DataRow drSource in dtSources.Rows)
    {
        int? iID = drSource.Field<int?>("ID");
        string sDescrption = drSource.Field<string>("Description"); 
    }
}
使用(DataTable dtSources=SQLHelper.Fetch(sQuery))
{
foreach(dtSources.Rows中的DataRow drSource)
{
int?iID=drSource.Field(“ID”);
字符串sDescrption=drSource.Field(“说明”);
}
}

同意Richard的答案,只是更好地使用

int iID = Convert.ToInt32(drSource["ID"]);

将行值转换为int变量的另一种方法是使用“object”并将其转换为Int32,如下所示:


intiid=Convert.ToInt32(行字段(“ID”)

drSource.Field(“ID”)。试试这个,让我知道。你试过了吗?它能工作吗?请看下面我的评论-实际上查询返回了DbNull值。所以,问题在于数据,而不是字段扩展。每个人都提供了有用的信息,谢谢。在这种情况下,“不太强”的转换,例如
intiid=(int)drSource[“ID”]
intiid=Convert.ToInt32(drSource[“ID”])
做到了这一点(因为
int iID=drSource.Field(“ID”);
甚至不允许隐式对int进行转换),但事先检查“可转换性”可能也是一个好主意。实际上,如果字段的类型很短,则需要使用Field(“ID”)。顺便说一句,为什么它很短,如果在数据库中(如您提供的)您有int,而不是小int。这个答案没有意义,因为OP的
字段(“ID”)
也有相同的功能。没有它的工作原理,最好使用int iID=Convert.ToInt32(drSource[“ID”]);(int)drSource[“ID”]对我不起作用。我必须使用上述答案