我正在编写一些带有SqlDataReader并处理结果的辅助函数。现在通常你会像这样构造循环:
while(reader.read()){
// Read fields
}
但是我将函数传递给已经位于一行的读者,在这种情况下我希望它处理当前行。如果在调用函数之前未调用read(),则上面的代码将仅输出整个结果集。
我希望函数执行以下操作:
if(!reader._dataReady)
rowExists = reader.read() // Read
while(rowExists){
// read fields
rowExists = reader.read()
}
_dataReady是SqlDataReader的实际成员,似乎可以做我需要的,但它是私有的!当然,有一种方法可以确定读者是否位于实际行上,而不是尝试读取字段并捕获异常。
答案 0 :(得分:2)
为什么不只是继承SqlDataReader,并创建Read()方法?我现在在我的所有项目中都有它:
public class SafeDataReader : IDataReader, SqlDataReader
{
public IDataReader reader {get;set;}
public int GetInt32(string aFieldName, int aDefault);
public int? GetInt32Nullable(string aFieldName);
....
}
答案 1 :(得分:1)
您可以使用FieldCount属性。根据{{3}},如果没有位于有效的记录集中,它将返回零。
其他一些解决方案:
将Read()
循环完全放在辅助方法之外(并且始终只在当前行上运行)
在帮助程序方法中完成Read()
循环 ,并始终传递未提升的新数据读取器
在数据阅读器之外做第一个Read()
,在助手方法中继续Read()
循环,并始终假设数据阅读器已经前进到第一个记录。
可能过度杀戮:写一个IDataReader的包装实现,它将所有调用转发给底层数据读取器(可能通过构造函数传入),但是暴露了一个属性,指示是否曾调用过Read。
< / LI> 醇>答案 2 :(得分:1)
反思很危险但通常很有用。这是一个扩展
public static bool? DataReady(this SqlDataReader rd) {
var sharedState = rd.GetType()?.GetField("_sharedState",
BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(rd);
return (bool?)sharedState?.GetType().GetField("_dataReady",
BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(sharedState);
}
答案 3 :(得分:0)
这有点超载了目的,但以下情况应该有效:
rowExists = reader.FieldCount > 0;
我怀疑你会发现自己遇到了一个设计问题,你在你的代码中的不同位置做了Read()。尝试在方法中仅进行数据操作(并将其作为IDataRecord
而不是IDataReader
传递),并将记录遍历逻辑留给调用者。