为什么DapperRow.GetType()返回null? [英] Why DapperRow.GetType() return null?

查看:57
本文介绍了为什么DapperRow.GetType()返回null?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知,Object.GetType()永远不应返回null.(

我怀疑动态或私有类型是null的原因,所以我编写了用于测试的类库:

 命名空间库{公开课Blah{公共静态动态SecretObject;静态Blah(){SecretObject =新的PrivateType();}}类PrivateType{}} 

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

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

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

解决方案

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

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

DapperRow 实现 System.Dynamic.IDynamicMetaObjectProvide 接口,该接口要求自定义 DynamicMetaObject 的实现,本质上是劫持并覆盖可以针对动态类型调用的方法以及这些调用应转换为的方法.在这种情况下,对DapperRow的IDictionary.Item getter或 DapperRow.SetValue 以外的任何东西的调用都将失败,因为它们始终被路由到这两个调用,但是值将为

  public bool TryGetValue(字符串名称,输出对象值){var index = table.IndexOfName(name);如果(索引< 0){//不存在值= null;返回false;}...} 

那时,对空动态值调用的任何方法都将引发 RuntimeBinderException :

RuntimeBinderException:无法对null执行运行时绑定参考

您可以通过将 GetType()替换为另一个将引发完全相同的异常的调用来轻松验证该假设:

  var rec = cn.Query(将getdate()选择为D").Single();var t = rec.AsEnumerable();Console.WriteLine(t.ToList()); 

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

  var rec = cn.Query(将getdate()选择为D").Single();var t = rec.D.GetType();Console.WriteLine(t.Name); 

As far as I knew, Object.GetType() should never return null. (related discussion)

Dapper .Query() return private class DapperRow instances to be treated as dynamic objects. I found a strange thing: DapperRow's .GetType() return null.

Here's the sample code to reproduce the problem. Create a C# project, reference Dapper and open a connection to SQL Server (or other database), use .Query() to execute simple select query and retrieve the first row of result. Use GetType() to get the type of result object, the return value is 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
}

I suspect that dynamic or private type is the cause of null, so I write my class library for test:

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

In another project, get the dynamic type static field and call GetType():

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

According to the test result, even cast private type as dynamic, I still can get the private type information from GetType(), why DapperRow.GetType() return null?

解决方案

DapperRow is specifically built and utilized within Dapper to provide highly optimized row returns without reiterating header information. This is to help condense the size of the object and reduce redundant data, making it more efficient.

However, it would appear that the StackExchange team took the meta programming even further than a first glance would indicate.

DapperRow implements the System.Dynamic.IDynamicMetaObjectProvide interface, which requires that the GetMetaObject method be implemented:

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

DapperRowMetaObject is a custom implementation of DynamicMetaObject that essentially hijacks and overrides what methods can be invoked against the dynamic type and what those calls should translate to. In this case, calls to anything other than the DapperRow's IDictionary.Item getter or the DapperRow.SetValue will fail since they are always routed to those two calls, but the value will be defaulted to null for any "get" calls where the target property does not exist in the table.

public bool TryGetValue(string name, out object value)
{
    var index = table.IndexOfName(name);
    if (index < 0)
    { // doesn't exist
        value = null;
        return false;
    }
    ...
}

At that point, any methods invoked on a null dynamic value will throw a RuntimeBinderException:

RuntimeBinderException: Cannot perform runtime binding on a null reference

You can easily test this hypothesis by replacing GetType() with another call that will throw the exact same exception:

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

Keep in mind, the underlying type information of any properties on the dynamic object itself can still be accessed directly:

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

这篇关于为什么DapperRow.GetType()返回null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆