DapperRow.GetType ()이 null을 반환하는 이유는 무엇입니까?

c# dapper types

문제

내가 아는 한, Object.GetType ()은 null을 반환해서는 안됩니다. ( 관련 토론 )

Dapper .Query ()는 동적 객체로 취급 될 개인 클래스 DapperRow 인스턴스를 반환합니다. 나는 이상한 것을 발견했다 : DapperRow의 .GetType ()은 null을 돌려 준다.

다음은 문제를 재현 할 수있는 샘플 코드입니다. C # 프로젝트를 만들고 Dapper를 참조하고 SQL Server (또는 다른 데이터베이스)에 대한 연결을 열고 .Query ()를 사용하여 간단한 select 쿼리를 실행하고 결과의 첫 번째 행을 검색합니다. 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
}

여기에 이미지 설명을 입력하십시오.

다이나믹 또는 프라이빗 타입이 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 팀은 첫눈에 알 수있는 것보다 훨씬 더 많은 메타 프로그래밍을 수행 한 것으로 보입니다.

DapperRowSystem.Dynamic.IDynamicMetaObjectProvide 인터페이스를 구현합니다.이 인터페이스에서는 GetMetaObject 메서드를 구현 해야 합니다.

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

DapperRowMetaObjectDynamicMetaObject사용자 정의 구현 으로, 동적 유형에 대해 호출 할 수있는 메소드와 변환해야 할 호출을 기본적으로 하이재킹하고 대체합니다. 이 경우, DapperRow의 IDictionary.Item 게터 나 이외의 다른 통화 DapperRow.SetValue 그들은 항상 두 통화를 라우팅하기 때문에 실패 할 것이다, 그러나 값이됩니다 null로 디폴트 하나가 "GET"여기서 target 속성 호출을 위해 테이블에 존재하지 않습니다.

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

그 시점에서, null의 동적 인 값으로 불려가는 메소드는, RuntimeBinderException 를 throw합니다.

RuntimeBinderException : null 참조에서 런타임 바인딩을 수행 할 수 없습니다.

GetType() 을 똑같은 예외를 throw하는 다른 호출로 대체하여이 가설을 쉽게 테스트 할 수 있습니다.

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


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.