DataRow.Field <T>(字符串列)抛出无效的强制转换异常

tha*_*Guy 8 c# datarow

美好的一天,

IDE Visual Studio 2010
.NET 3.5
平台 WinForms

SO问题" 从DataRow获取价值之间的差异 "是指.

我有一个带有列的数据库表[ID] INT IDENTITY(1, 1) NOT NULL PRIMARY KEY.查询此表并将值存储在局部变量中时,我得到一个无效的强制转换异常; 示例代码:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

当步进执行并在故障线路上执行"快速监视"时,我发现通过将线路更改为drSource.Field<object>("ID"),单元格值类型是short而不是int.为什么会在表定义中清楚地表明这种情况int呢?此外,short应当隐式转换为int因为short比较小,应该"适合"的权利?

小智 11

如果您的列是可以为null的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"); 
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的列是可以为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"); 
    }
}
Run Code Online (Sandbox Code Playgroud)


Him*_*arg 7

同意Richard的回答更好用,

int iID = Convert.ToInt32(drSource["ID"]);
Run Code Online (Sandbox Code Playgroud)


Ric*_*ard 5

出于好奇,如果您自己从键/值集合中明确地将其强制转换会怎样?

int iID = (int)drSource["ID"];
Run Code Online (Sandbox Code Playgroud)

  • 不起作用,最好使用int iID = Convert.ToInt32(drSource [“ ID”]); (3认同)
  • 这个答案没有意义,因为OP的`Field &lt;int&gt;(“ ID”)`所做的相同。 (2认同)

Ser*_*kiy 5

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

public static T Field<T>(this DataRow row, string columnName)
    {
        DataSetUtil.CheckArgumentNull<DataRow>(row, "row");
        return UnboxT<T>.Unbox(row[columnName]);
    }
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)