DapperRow
在 Dapper 中专门构建和使用,以提供高度优化的行返回,而无需重复标头信息。这是为了帮助压缩对象的大小并减少冗余数据,从而提高效率。
然而,StackExchange 团队似乎比乍一看更进一步地采用了元编程。
DapperRow
实施System.Dynamic.IDynamicMetaObjectProvide
接口,这要求获取元对象 https://github.com/StackExchange/Dapper/blob/61e965eed900355e0dbd27771d6469248d798293/Dapper/SqlMapper.DapperRow.cs#L80实施方法:
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(
System.Linq.Expressions.Expression parameter)
{
return new DapperRowMetaObject(parameter,
System.Dynamic.BindingRestrictions.Empty, this);
}
DapperRowMetaObject
is a 自定义实现 https://github.com/StackExchange/Dapper/blob/61e965eed900355e0dbd27771d6469248d798293/Dapper/SqlMapper.DapperRowMetaObject.cs of DynamicMetaObject
它本质上劫持并覆盖了可以针对动态类型调用哪些方法以及这些调用应该转换为什么。在这种情况下,调用除 DapperRow 的 IDictionary.Item getter 或DapperRow.SetValue
将会失败,因为它们总是被路由到这两个调用,但值将是默认为空 https://github.com/StackExchange/Dapper/blob/61e965eed900355e0dbd27771d6469248d798293/Dapper/SqlMapper.DapperRow.cs#L42对于表中不存在目标属性的任何“get”调用。
public bool TryGetValue(string name, out object value)
{
var index = table.IndexOfName(name);
if (index < 0)
{ // doesn't exist
value = null;
return false;
}
...
}
此时,对空动态值调用的任何方法都将抛出RuntimeBinderException
:
RuntimeBinderException:无法对 null 执行运行时绑定
参考
您可以通过替换来轻松检验这个假设GetType()
另一个调用将抛出完全相同的异常:
var rec = cn.Query("select getdate() as D").Single();
var t = rec.AsEnumerable();
Console.WriteLine(t.ToList());
请记住,任何属性的基础类型信息on动态对象本身仍然可以直接访问:
var rec = cn.Query("select getdate() as D").Single();
var t = rec.D.GetType();
Console.WriteLine(t.Name);