秘密を暴くNet 2.0のEvalメソッド

5945 ワード

実際にEvalメソッドはTemplateControlであり、Systemである.Web.UI.PageとSystemWeb.UI.UserControlはすべてTemplateControlに継承されているので、PageとUserControlで直接メソッドを呼び出すことができます.Page.Evalメソッドは、ASP.でデータバインド式をよりよく書くのに役立ちます.NET   1.x時代、データバインド式の一般的な形式は:
<%# DataBinder.Eval(Container,“DataItem.Name”)   %>

そしてASP.NET 2.0では、同じコードを書くことができます.
<%# Eval(“Name”)%>


ASP.NET 2.0はどうやって実現したのでしょうか?まずEval法から反射によって研究した.NET fromwork 2.0クラスライブラリのソースコードでは、この方法がこのように実現されていることがわかります.
protected internal object Eval(string expression)

{

    this.CheckPageExists();

    return DataBinder.Eval(this.Page.GetDataItem(), expression);

} 

最初の行は管理する必要はありません.これは呼び出し時にPageオブジェクトがあるかどうかをチェックし、ない場合は例外を放出します.重要なのは2行目です.
return   DataBinder.Eval(this.Page.GetDataItem(),   expression); 

Page.GetDataItem()も2.0に新たに追加された方法であり、ASPに取って代わるものである.NET   1.xのContainer.DataItem. GetDataItem()の方法をよく知らないようで、私たちもEvalの原理を理解するのは難しい.GetDataItemの実装も簡単です.
public object GetDataItem()

{

    if ((this._dataBindingContext == null) || (this._dataBindingContext.Count == 0))

    {

        throw new InvalidOperationException(SR.GetString("Page_MissingDataBindingContext"));

    }

    return this._dataBindingContext.Peek();

}   

内部オブジェクトがあることに気づきましたDataBindingContextは、ソースコードを調べることでStackタイプのものであることを発見しました.だから彼はPeekの方法を持っています.このコードは分かりやすく、まずこのStackがインスタンス化されているかどうかを判断し、その後、このStackの中に要素があるかどうかを判断し、Stackがインスタンス化されていないか、要素がない場合は異常を投げ出す.最後に、このスタックの上部の要素を返します.    ASP.NET 2.0はStackを使っていわゆるDataItemを保存して、私達はすぐにこのスタックのために要素とポップアップする要素の方法を調べました:Control.DataBindメソッド:
protected virtual void DataBind(bool raiseOnDataBinding)

{

    bool flag1 = false;//                  ,   DataItem  ,      。   

    if (this.IsBindingContainer)//             ,                INamingContainer   

    {

        bool flag2;

        object obj1 = DataBinder.GetDataItem(this, out   flag2);//             DataItem  ,      。   

        if (flag2 && (this.Page != null))//     DataItem   

        {

            this.Page.PushDataBindingContext(obj1);// DataItem  ,PushDataBindingContext    _dataBindingContext Push     

            flag1 = true;

        }

    }

    try

    {

        if (raiseOnDataBinding)//          DataBinding   。   

        {

            this.OnDataBinding(EventArgs.Empty);

        }

        this.DataBindChildren();//          ,       DataItem,     DataItem    ,  ,        Eval  GetDataItem  ,         DataItem    。   

    }

    finally

    {

        if (flag1)//       ,      。   

        {

            this.Page.PopDataBindingContext();//PopDataBindingContext    _dataBindingContext Pop     

        }

    }

}

これで、ASPを完全に理解することができます.NET 2.0のGetDataItenとEvalの方法の動作の原理
効率について:
間違いなく強いタイプの変換Containerの効率は最も高く、Evalは最終的にDataBinderを呼び出す.Evalメソッド、DataBinder.Evalは反射を用いてデータを取得するが,これは明らかに強いタイプのデータ変換に及ばない.  
様々な方法を比較することができます.
((Type)   Container.DataItem).Property  

この方法は反射が存在しないため効率が最も高い.次に、
((Type)   GetDataItem()).Property 

この方法の効率が悪いのは,StackのPeek動作が1つ増えたためであり,もちろん,実際にはこの点の差は無視できる.最後に、EvalまたはDataBinderです.Eval、この2つの方法はいずれも反射を使用して属性またはインデックスメンバーを検索し、効率が大幅に低下します.もう一つの注目すべき問題は、INamingContainerインタフェースが実装されたすべてのControlが、Controlにあるため、IDataItemContainerインタフェースを実装すべきであることである.DataBindの場合、INamingContainerインタフェースが実装されていることが判明すると、そのDataItemを探そうとし、IDataItemContainerが実装されていない場合、DataBinder.GetDataItemメソッドでは、反射を使用して、コントロールにDataItemという属性メンバーがあるかどうかを確認します.これは明らかに私たちが望んでいるものではありません. 
実はASP.NETにはもう一つのタグインタフェースがある:INonBindingContainer、INamingContainerインタフェースを実現するコントロールは同時にこれを実現することを選択してASPを命令することができる.NETはDataItemを探しに行かないが、残念ながらマイクロソフトが何の目的でこのインタフェースがinternalなのか分からない......
実は効率の面ではあまり重視する必要はありません.Eval表現はとてもきれいで、そんなに極端に効率を重視していても、GeDataItemはいい選択です.間違いなく強いタイプの変換Containerの効率は最も高く、Evalは最終的にDataBinderを呼び出す.Evalメソッド、DataBinder.Evalは反射を用いてデータを取得するが,これは明らかに強いタイプのデータ変換に及ばない.