我正在尝试扩展DataRow扩展的Field方法,以添加一个参数来检查列是否存在:
public static T? FieldValue<T>(
this DataRow row,
string columnName,
bool checkColumn = false) where T : struct
{
return
checkColumn
&& !row.Table.Columns.Contains(
columnName)
? default(T)
: row.Field<T>(
columnName);
}这对于int,datetime等很有效。但是,当我尝试将它与string一起使用时,它显示错误:
The type string must be non-nullable如果数据库中有空值,我也会收到错误:
Cannot cast DBNull.Value to type 'System.Decimal'有没有一种方法可以无缝地扩展Dataextension?
发布于 2017-07-20 05:52:03
正如Markus所指出的,这里有两个挑战。一个是关于结构与值类型,另一个是关于你必须处理空值的事实。
第二个问题很容易处理:只需像这样向您的实现添加一个?:row.Field<T?>(columnName),您的异常就会消失。
然而,第一个问题是一个令人讨厌且经常遇到的问题。我不知道有什么好办法来解决这个问题。还是让我提个建议吧:
根据上面的代码,我假设您很乐意返回Nullable类型,即使对于不可空的列也是如此。下面是你可以做的一些事情,在你已经拥有的基础上支持引用类型,并且仍然避免太多的代码重复:
// value type version
public static T? FieldValueStruct<T>(this DataRow row, string columnName, bool checkColumn = false)
where T : struct
{
return row.GetValue(columnName, checkColumn, default(T), row.Field<T? /*with a question mark!!!*/ >);
}
// reference type version
public static T FieldValueClass<T>(this DataRow row, string columnName, bool checkColumn = false)
where T : class
{
return row.GetValue(columnName, checkColumn, default(T), row.Field<T>);
}
// shared amongst value and reference type implementation
private static T GetValue<T>(this DataRow row, string columnName, bool checkColumn, T defaultValue, Func<string, T> getter)
{
return checkColumn && !row.Table.Columns.Contains(columnName)
? defaultValue
: getter(columnName);
}有了这些代码,您就可以获得所需的功能,但代价是:在调用这些方法时,您需要指定类型参数(就像现在一样),因为类型推断将不起作用(here is why)。
string s;
// no type inference, type parameter must be specified
s = row.FieldValueClass<string>("test");此外,您还需要在调用中区分值类型版本和引用类型版本,这是很不美观的。为什么我们需要对这些方法使用两个不同的名称?这样做的原因是,您不能通过简单地添加不同的类型约束来重载方法(参见here)。
类型推断主题可以通过使用out参数来解决,然而,这也带来了一系列缺点...
// value type version that works with type inference
public static void FieldValueStruct<T>(this DataRow row, string columnName, out T? value, bool checkColumn = false)
where T : struct
{
value = row.GetValue(columnName, checkColumn, default(T), row.Field<T?>);
}
// reference type version that works with type inference
public static void FieldValueClass<T>(this DataRow row, string columnName, out T value, bool checkColumn = false)
where T : class
{
value = row.GetValue(columnName, checkColumn, default(T), row.Field<T>);
}现在,您可以在不使用type参数的情况下调用方法,如下所示:
string s;
// with type inference, doesn't work with properties, though, only with fields
row.FieldValueClass("test", out s);不幸的是,这不适用于属性-仅适用于字段。
你看,这个世界是邪恶的,有时候,我们对此无能为力。;)
基于您的评论的更新:
下面的代码稍微改变了你的语义,但也许这没什么问题:
public static T FieldValue<T>(this DataRow row, string columnName, bool checkColumn = false)
{
return checkColumn && !row.Table.Columns.Contains(columnName)
? default(T)
: row.Field<T>(columnName);
}调用此方法需要如下所示:
// this will return 0 if the column is not available, a null value from the database will cause an exception
int i = r.FieldValue<int>("test");
// this will return null if the column is not available, a null value from the database would be ok
int? iNullable = r.FieldValue<int?>("test");
// this will return null if the column is not available, a null value from the database would be ok
string s = r.FieldValue<string>("test");发布于 2017-07-20 03:30:38
第一条错误消息的原因是where-constraint:
where T : struct此约束要求用作类型参数的每个类型T都是值类型。string是一个引用类型,因此出现错误消息。为了解决这个问题,如果你不需要这个约束,你应该删除它。
对于空值问题,您应该检查列是否为空(如果存在),在这种情况下还应返回default(T)。可以使用DataRow.IsNull方法检查单元格是否为空。
https://stackoverflow.com/questions/45199333
复制相似问题