用 DynamicSqlDataReader 替换 SqlDataReader






3.73/5 (5投票s)
使用 .NET 4.0 的动态特性,从你的应用程序中移除这些字符串。
引言
这是一个非常简单的例子,展示了 .NET 4.0 的动态特性如何在类型化和非类型化之间提供帮助。它将 SqlDataReader
包装在 DynamcSqlDataReader
中,允许你将字段作为属性访问,而不是将包含列名的字符串值传递给方法。
使用代码
有些代码读起来像诗歌,不需要过多的解释。通过查看测试用例,你应该能够了解其预期用途。用于证明概念的数据库包含一个名为 Person 的表,其中包含以下字段:
- Id:
uniqueidentifier
(PK) - Name:
nvarchar(50)
非空 - Country:
nvarchar(50)
可空 - Age:
smallint
可空
测试用例
[TestClass]
public class PersonDataAccessTests
{
public void Theory_Read_Person_Table(Action<dynamic> assertion)
{
using (var connection = new SqlConnection(@"CONNECTION STRING HERE"))
{
using (var command = new SqlCommand("SELECT TOP 1 Id," +
"Name,Country,Age FROM Person", connection))
{
connection.Open();
var x = new DynamicSqlDataReader(command.ExecuteReader(
System.Data.CommandBehavior.CloseConnection));
while (x.Read())
{
assertion(x);
}
}
}
}
[TestMethod]
[ExpectedException(typeof(ColumnIsNotInResultSetException))]
public void Test_Read_Person_Table_Failure()
{
Theory_Read_Person_Table((x) =>
{
string s = x.NonExistingColumn;
});
}
[TestMethod]
public void Test_Read_Person_Table_Success()
{
Theory_Read_Person_Table((x) =>
{
Guid id = x.Id;
string name = x.Name;
string country = x.Country;
int? age = x.Age;
Assert.AreNotEqual(Guid.Empty, id);
Assert.AreEqual("Tim", name);
Assert.AreEqual("Belgium", country);
Assert.AreEqual(null, age);
});
}
}
实际代码
public class DynamicSqlDataReader : DynamicObject
{
private SqlDataReader reader;
public DynamicSqlDataReader(SqlDataReader reader)
{
this.reader = reader;
}
public bool Read()
{
return reader != null && (!reader.IsClosed) && reader.Read();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
try
{
var rawResult = reader.GetValue(reader.GetOrdinal(binder.Name));
result = rawResult == DBNull.Value ? null : rawResult;
return true;
}
catch (IndexOutOfRangeException)
{
throw new ColumnIsNotInResultSetException(binder.Name);
}
}
}
关注点
请提供一些反馈,并讨论如何使用新的动态特性。 我也知道,将 DbDataReader
而不是具体的 SqlDataReader
包装起来会更干净,但仅仅是为了展示新的动态特性的使用 :)