2017-03-23 15 views
3

私が知る限り、Object.GetType()はnullを返すべきではありません。 (related discussionなぜDapperRow.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 
} 

enter image description here

私は、ダイナミックまたはプライベートタイプが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" 

テストr私はまだGetType()からprivate型の情報を得ることができますが、なぜDapperRow.GetType()はnullを返しますか?

答えて

4

DapperRowは、ヘッダー情報を繰り返さずに、最適化された行リターンを提供するために、Dapper内で具体的に構築されて利用されます。これは、オブジェクトのサイズを圧縮し、冗長なデータを減らし、より効率的にするのに役立ちます。

しかし、StackExchangeチームは、最初の一見が示すよりもむしろメタプログラミングを行ったように見えます。

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

DapperRowMetaObjectは、本質的にハイジャック及び方法は、動的な型に対して呼び出すことができるかオーバーライドDynamicMetaObjectcustom implementationであり、どのようなもの呼び出し:

DapperRowSystem.Dynamic.IDynamicMetaObjectProvideGetMetaObject方法が実施されることを要求するインタフェースを実装しますに翻訳する必要があります。この場合、DapperRowのIDictionary.ItemゲッターまたはDapperRow.SetValue以外の呼び出しは、それら2つの呼び出しに常にルーティングされるため失敗しますが、ターゲットプロパティが存在しないすべての「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); 
+0

非常に明確な説明を!私の謎を解決してくれてありがとう。 – Darkthread

+0

@Darkthreadよろしくお願いします! –

関連する問題