System.Web.UI.DataBinder.Eval
メカニズムを使用してオブジェクトのプロパティにアクセスする必要があり、疑問が生じました:どのくらい速く動作し、そのような操作をさらに高速に実行できるのか?
それで、ちょっとしたテストが行われました。 まず、2つのクラス(仮想プロパティとオーバーライドされたプロパティのテスト用)を作成しました。これらのクラスのプロパティを参照します。
public class c1
{
string _str;
public c1( string str)
{
_str = str;
}
public string Str1 { get { return "1: " +_str; } }
public virtual string Str2 { get { return "2: " +_str; } }
}
public class c2 : c1
{
public c2( string str)
: base (str)
{
}
public override string Str2 { get { return "C" + base .Str2; } }
}
テスト自体:
c2 c = new c2( "str" );
//
for ( int i=0; i<ITERATIONS; i++)
{
String .Format( "Str1: {0}, Str2: {1}" , c.Str1, c.Str2);
}
// DataBinder
for ( int i=0; i<ITERATIONS; i++)
{
String .Format( "Str1: {0}, Str2: {1}" , DataBinder.Eval(c, "Str1" ), DataBinder.Eval(c, "Str2" ));
}
結果:
- 直接呼び出し:00:00:00.065(100%)
- DataBinder.Eval:00:00:01.135( 1746% )
うわー、17倍遅い! 同様のことが想定されていましたが。
速度を上げるために、Reflectionへの呼び出しをキャッシュすることが最初に提案されました(そのようなタスクがない場合)。 次に、アクセスコードをその場で生成して、アプローチをテストしました。
- 最初の呼び出しで、Reflectionを介してクラスとプロパティを調べます
- プロパティが定義または再定義されたクラスに行きます
- 1つのメソッドで構成されるクラスを作成します。特定のタイプのオブジェクトから目的のプロパティの値を取得します
- 構築されたメソッドを呼び出します
このトピックでは、 プロジェクト(29Kb)のダウンロードに興味がある世代コードは提供しません。
c2 c = new c2( "str" );
PropertyAccessor p1 = PEval.GetPropertyAccessor(c.GetType(), "Str1" );
PropertyAccessor p2 = PEval.GetPropertyAccessor(c.GetType(), "Str2" );
for ( int i=0; i<ITERATIONS; i++)
{
String .Format( "Str1: {0}, Str2: {1}" , p1.GetValue( c ), p2.GetValue( c ));
}
実行結果:
- キャッシュされたコール:00:00:00.065(100%)
素晴らしい結果です! 速度は直接呼び出しに匹敵しますが、今回はいくつかの起動が100%未満であることがありました。 メソッドを持つクラスが記憶されており、そのようなクラスの存在を確認せずに常にアクセスされたため、彼はキャッシュされた呼び出しを呼び出しました。
実験を完了するために、構築されたクラスをキャッシュし、必要に応じて作成する静的クラスが作成されました。
c2 c = new c2( "str" );
for ( int i=0; i<ITERATIONS; i++)
{
String .Format( "Str1: {0}, Str2: {1}" , PEval.GetValue(c, "Str1" ), PEval.GetValue(c, "Str2" ));
}
実行結果:
- PEval.GetValue:00:00:00.090(138%)
直接呼び出しよりもわずか38%遅くなります。 いくつかの打ち上げでは平均結果が150%でしたが、それでも1746%ではありません。
完全なテスト出力:
Create PropertyAccessor for TestDataBinding.c1.Str1
Create PropertyAccessor for TestDataBinding.c2.Str2
=========================
ITERATIONS: 100000
: 00:00:00.065 (100%)
PEval.GetValue: 00:00:00.090 (138%)
: 00:00:00.065 (100%)
DataBinder.Eval: 00:00:01.135 (1746%)
=========================
TestDataBinding.c2 (TestDataBinding.PropEvaluator.PropertyAccessor) [200003]
TestDataBinding.c1_Str1_Accessor => Str1 (G) [100002]
TestDataBinding.c2_Str2_Accessor => Str2 (G) [100001]
TestDataBinding.c1 (TestDataBinding.PropEvaluator.PropertyAccessor) [2]
TestDataBinding.c1_Str1_Accessor => Str1 (G) [100002]
=========================
200万回の呼び出し:
=========================
ITERATIONS: 1000000
: 00:00:00.930 (100%)
PEval.GetValue: 00:00:01.085 (116%)
: 00:00:00.738 (79%)
DataBinder.Eval: 00:00:10.976 (1180%)
=========================
そしてさらに10倍:
=========================
ITERATIONS: 10000000
: 00:00:06.802 (100%)
PEval.GetValue: 00:00:10.917 (160%)
: 00:00:07.017 (103%)
DataBinder.Eval: 00:01:45.476 (1550%)
=========================
他に追加できるもの:
- プロパティの値を変更するメソッドを作成します
- 追加の機能を使用して、プロパティへのアクセスクラスを拡張します。プロパティの表示名、値を文字列にフォーマットする/文字列から値を解析、値を検証する
- 1つのプロパティではなく、チェーン
PEval.GetValue(o, "Prop1.Prop2.Prop4")
追加1。
より高度なバージョンのクラス図:
コードジェネレータークラス図: