.NET TIPS

[ASP.NET]DataBinder.Evalメソッドを使用するメリット/デメリットは?

デジタルアドバンテージ
2003/09/19

 ASP.NETにおいて、Repeater、DataList、DataGridなどのWebサーバ・コントロールでデータ連結を行う場合、データ連結式の記述でContainer.DataItemに対してDataBinder.Evalメソッドを使用する場合がある。しかし実のところ、データ連結式においてDataBinder.Evalメソッドは必ずしも必要というわけではない。このメソッドを使用するメリット/デメリットについてまとめてみる。

Container.DataItemについての復習

 「TIPS:[ASP.NET]Container.DataItemの正体は?」で解説しているように、データ連結式内ではContainer.DataItem」によりデータソース(コントロールのDataSourceプロパティで指定したコレクション)の各要素を参照することができる。

 例えば、aspxファイルで次のようなRepeaterコントロールを記述し、

  <asp:Repeater id="MyRepeater" runat="server">
    <ItemTemplate>
      <%# Container.DataItem %>
    </ItemTemplate>
  </asp:Repeater>

 このコントロールに対して、次のようなデータソースを設定した場合を考えてみる。

string[] cmajor = {"C", "C#", "D", "D#", "E"};
MyRepeater.DataSource = cmajor;

 MyRepeater.DataBindメソッドを呼び出してデータ連結を行った場合には、上記の<ItemTemplate>要素部分が5つの子コントロールに展開され、それぞれの<%# Container.DataItem %>の部分は文字列配列の各要素に置き換えられる。

 この場合には、反復されるデータソースの各要素そのものをデータ連結式で表示しているわけだが、各要素の特定のプロパティをRepeaterコントロールで表示したい場合について次に考えてみよう。

キャストが不要となるDataBinder.Evalメソッド

 ここでは、string型のプロパティ「Name」と、DateTime型のプロパティ「BirthDay」を持つクラス「Composer」が定義されているとしよう。そして次のようにして、このクラスのオブジェクトからなるコレクションを作成し、それをデータソースに設定したとする。

ArrayList comps = new ArrayList();
comps.Add(new Composer("Bach", "1685/3/21"));
comps.Add(new Composer("Mozart", "1756/1/27"));
comps.Add(new Composer("Beethoven", "1770/12/16"));
MyRepeater.DataSource = comps;

 今回Repeaterコントロールにより実際に表示したい項目は、各ComposerオブジェクトのNameプロパティとBirthDayプロパティである。このようなデータソースを設定した場合、データ連結式においてContainer.DataItemはデータソース内の各Composerオブジェクトを参照する。よって、各オブジェクトについてNameプロパティとBirthDayプロパティを表示するには、

<%# Container.DataItem.Name %>
<%# Container.DataItem.BirthDay %>

と記述したいところだが、これはコンパイル・エラーとなる。DataItemプロパティの型はobject型であり、objectクラスは当然ながらNameやBirthDayといったプロパティは持たないためだ(どのようなデータソースであっても参照できるように、DataItemプロパティはobject型である)。

 この場合Container.DataItemをComposer型にキャストする必要があり、正しいデータ連結式の記述は次のようになる。

<%# ((Composer)Container.DataItem).Name %>
<%# ((Composer)Container.DataItem).BirthDay %>

 さて、ここでDataBinder.Evalメソッドの出番となる。このメソッドを使用すると、上の2行は次のように「キャストなし」で記述することができる。

<%# DataBinder.Eval(Container.DataItem, "Name") %>
<%# DataBinder.Eval(Container.DataItem, "BirthDay") %>

 これがDataBinder.Evalメソッドを使用する第1のメリットである。

 Composerクラスを使用した実際のサンプル・プログラムとその実行結果は次のようになる。

サンプル・プログラムの実行結果

DataBinder.Evalメソッドの動作

 DataBinderクラス(System.Web.UI名前空間)のstaticなメソッドであるEvalメソッドはデータ連結式内で使用される場合がほとんどであるが、データ連結式に依存した特別な機能を持っているわけではない。次のような簡単なC#のサンプル・プログラムを例にしてDataBinder.Evalメソッドの動作について見てみよう。

// binder.cs

using System;
using System.Web.UI;

public class BinderEvalTest {
  static void Main() {

    string[] colors = {"red", "green", "blue"};

    int len1 = colors.Length;
    int len2 = (int)DataBinder.Eval(colors, "Length");

    Console.WriteLine("{0}, {1}", len1, len2);
    // 出力:3, 3

    int len3 = colors[1].Length;
    int len4 = (int)DataBinder.Eval(colors, "[1].Length");
    int len5 = (int)DataBinder.Eval(colors[1], "Length");

    Console.WriteLine("{0}, {1}, {2}", len3, len4, len5);
    // 出力:5, 5, 5

    string str1 = colors.ToString();
    // string str2
    //   = (string)DataBinder.Eval(colors, "ToString()");
    // 実行時にエラーとなる。

  }
}

// コンパイル方法:csc binder.cs
DataBinder.Evalメソッドをテストするサンプル・プログラム(binder.cs)

 最初の例はDataBinder.Evalメソッドによりプロパティの値を取得している。

int len1 = colors.Length;
int len2 = (int)DataBinder.Eval(colors, "Length");

 DataBinder.Evalメソッドは、第1パラメータで指定したオブジェクトに対して、第2パラメータで指定した名前を持つプロパティの値を取得することができる。

 このような処理が可能な理由は、.NET Frameworkが「リフレクション」と呼ばれる機能を持っているためだ。リフレクション機能を使用すると、実行時に、オブジェクトが定義しているプロパティ名やメソッド名を列挙したり、文字列で指定したプロパティの値の取得や、文字列で指定したメソッドを呼び出したりできる。

 DataBinder.Evalメソッドは、次のような大括弧を伴うインデクサによる値の取得時にも使用可能だ。

int len3 = colors[1].Length;
int len4 = (int)DataBinder.Eval(colors, "[1].Length");
int len5 = (int)DataBinder.Eval(colors[1], "Length");

 このように、DataBinder.Evalメソッドの処理はメソッドの2つのパラメータを連結したものを実行するようなイメージだが、メソッドの呼び出しはできない。

string str1 = colors.ToString();
string str2 = (string)DataBinder.Eval(colors, "ToString()");

 変数str2に代入を行っている2行目の記述は、実行時にエラーとなる。

DataBinder.Evalメソッドによる文字列の整形

 DataBinder.Evalメソッドには、キャストが不要となることに加えて、もう1つの有用な機能がある。文字列の整形である。

 Composerクラスを用いた最初のサンプル・プログラム(composer.aspx)ではDateTime型のプロパティBirthDayをそのまま表示していたが、これを“YYYY-MM-DD”の形式で表示したいとしよう。DataBinder.Evalメソッドを使わずに行う1つの方法は、次のようなメソッドを用意することだ。

public string GetYYYYMMDD(object o) {
  Composer c = (Composer)o;
  return String.Format("{0:yyyy-MM-dd}", c.BirthDay);
}

 Stringクラス(System名前空間)のFormatメソッドは、指定した書式でオブジェクトを文字列化するためのstaticなメソッドだ。このようなメソッドを用意したとすると、データ連結式の記述でこのメソッドを直接呼び出すことができる。

<%# GetYYYYMMDD(Container.DataItem) %>

 オーバーロードされた別バージョンのDataBinder.Evalメソッドを使えば、文字列を整形するためのメソッドを用意せずに次のようにして同等な記述が可能である。

<%# DataBinder.Eval(Container.DataItem, "BirthDay", "{0:yyyy-MM-dd}") %>

 このDataBinder.Evalメソッドは、反復される要素の特定のプロパティを書式付きでテキスト化することができる。第3パラメータには書式を表す文字列を指定する。このDataBinder.Evalメソッドは内部でString.Formatメソッドを呼び出しているようで、このパラメータにはString.Formatメソッドの第1パラメータと同様な書式文字列が指定可能だ。

DataBinder.Evalメソッドの欠点

 データ連結式では、反復されるデータソースの項目に対して、そのプロパティを書式付きで表示することが多い。DataBinder.Evalメソッドは、そういった処理の記述を容易にするために用意されたメソッドであるといえる。

 しかし、DataBinder.Evalメソッドはリフレクション機能を使用しているため、実行に時間がかかるという欠点がある。

 上記のサンプル・プログラム(binder.cs)を少し改造して、len1からlen5までの呼び出しを100万回実行するのにかかった時間を筆者のPCで計測したところ、len1、len3が計測不可能なぐらい一瞬で終わるのに対して、

「int len2 = (int)DataBinder.Eval(colors, "Length");」は約4秒、
「int len4 = (int)DataBinder.Eval(colors, "[1].Length");」は約7秒、
「int len5 = (int)DataBinder.Eval(colors[1], "Length");」は約3秒、

の時間がかかった。ページ内にデータ連結を行う項目が多いような場合には注意が必要だ。サーバに負荷がかかる場合には、記述は多少煩雑になるがDataBinder.Evalメソッドの使用をやめることができる。End of Article

カテゴリ:Webフォーム 処理対象:コントロール
使用ライブラリ:Repeaterコントロール(System.Web.UI.WebControls名前空間)
使用ライブラリ:DataBinderクラス(System.Web.UI名前空間)
使用ライブラリ:Stringクラス(System名前空間)
関連TIPS:[ASP.NET]Container.DataItemの正体は?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]DataGridコントロールのハイパーリンク列で複数のパラメータをデータ連結するには?
[ASP.NET]Container.DataItemの正体は?
[ASP.NET]DataGridコントロールの行に通し番号を付けるには?
[ASP.NET]DataGridコントロールでテンプレート列のセルの値を取得するには?
[ASP.NET]DataGridコントロールの各セルにアクセスするには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間