据我所知,Object.GetType()永远不要返回null。 (related discussion

Dapper .Query()返回私有类DapperRow实例,将其视为动态对象。我发现了一件奇怪的事情:DapperRow的.GetType()返回null。

这是重现该问题的示例代码。创建一个C#项目,引用Dapper并打开与SQL Server(或其他数据库)的连接,使用.Query()执行简单的选择查询并检索结果的第一行。使用GetType()获取结果对象的类型,返回值为null。

using (SqlConnection cn = new SqlConnection(csSql))
{
    var rec = cn.Query("select getdate() as D").Single();
    var t = rec.GetType(); // t == null
    Console.WriteLine(t.Name); // null reference exception
}


c# - 为什么DapperRow.GetType()返回null?-LMLPHP

我怀疑动态或私有类型是null的原因,因此我编写了我的类库进行测试:

namespace Lib
{
  public class Blah
  {
    public static dynamic SecretObject;
    static Blah()
    {
        SecretObject = new PrivateType();
    }
  }
  class PrivateType
  {
  }
}


在另一个项目中,获取动态类型静态字段并调用GetType():

    dynamic obj = Lib.Blah.SecretObject;
    Console.WriteLine(obj.GetType().Name); // "Lib.PrivateType"


根据测试结果,即使将私有类型转换为动态类型,我仍然可以从GetType()获取私有类型信息,为什么DapperRow.GetType()返回null?

最佳答案

DapperRow是在Dapper中专门构建和利用的,以提供高度优化的行返回,而无需重复标题信息。这是为了帮助压缩对象的大小并减少冗余数据,从而使其效率更高。

但是,似乎StackExchange团队将元编程带入了比乍看之下还要远的地方。

DapperRow实现System.Dynamic.IDynamicMetaObjectProvide接口,该接口要求实现GetMetaObject方法:

System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(
    System.Linq.Expressions.Expression parameter)
{
    return new DapperRowMetaObject(parameter,
        System.Dynamic.BindingRestrictions.Empty, this);
}


DapperRowMetaObjectDynamicMetaObjectcustom implementation,本质上是劫持和替代可以针对动态类型调用的方法以及这些调用应转换为的方法。在这种情况下,对DapperRow的IDictionary.Item getter或DapperRow.SetValue以外的任何东西的调用都将失败,因为它们始终被路由到这两个调用,但是对于目标属性为“ get”的任何调用,其值为defaulted to null表中不存在。

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());


请记住,仍然可以直接访问动态对象本身上任何属性的基础类型信息:

var rec = cn.Query("select getdate() as D").Single();
var t = rec.D.GetType();
Console.WriteLine(t.Name);

关于c# - 为什么DapperRow.GetType()返回null?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42966787/

10-13 02:38