2009-04-19 9 views
3
private Equipment GenerateDirtyPropertiesOnEntity(Equipment updatedEntity) 
    { 
     updatedEntity.DirtyProperties.Clear(); 
     Equipment originalEntity = GetEquipmentByGuid(updatedEnitity.Guid.Value); 
     Type myType = updatedEntity.GetType(); 
     System.Reflection.PropertyInfo[] properties = myType.GetProperties(); 
     foreach (System.Reflection.PropertyInfo p in properties) 
     { 
      if (p.GetValue(originalEntity, null) == null) 
      { 
       if (p.GetValue(updatedEntity, null) != null) 
        updatedEntity.DirtyProperties.Add(p.Name); 
      } 
      else 
      { 
       if (!(p.GetValue(originalEntity, null).Equals(p.GetValue(updatedEntity, null)))) 
        updatedEntity.DirtyProperties.Add(p.Name); 
      } 
     } 
     return updatedEntity; 
    } 

これを使用するとどれくらいのスピードが犠牲になるのですか? 誰かがこれを行うより良い方法を知っていますか?反射関連どのくらいスピードが犠牲ですか?

おかげで、事前

+0

オリジナルのものはオリジナルであるあなたの例の中では? – Svish

+0

はい。私のせい。私はそれを修正します。 – AlteredConcept

答えて

1

に私は、それが設定されています古いものと新しいプロパティ値を比較し、PostSharpを使用して、同様の何かを見て、そして汚れなどのオブジェクトにフラグを立てるんです。不動産レベルで同じことをするのはあまり難しくありません。

1

あなたが犠牲にしているスピードは、間違いなくこのことを知る唯一の方法です。

一般的に、私の経験では、プロパティに反映することは、せいぜい、直接アクセスする速度の約1/50になるようです。最悪の場合、それは200倍遅くなる可能性があります。この操作の頻度とプロパティの数によって、これは顕著な違いかもしれませんが、別の解決策が必要かどうかを判断するためにプロファイリングすることをお勧めします。

3

あなたは2つの質問を求めている:あなたはどのくらいの速さを失うている

  1. を?
  2. それを

質問#1行うにはそこより高速な方法です:

を最初の1への答えは:それは依存しています。手作業でプロパティチェックコードを書くことは、リフレクションコードよりも数倍高速になる可能性があります。しかし、実際にコードが呼び出される頻度によっては、実際には問題ではないかもしれません。コードが頻繁に呼び出されないと、最適化の手間がかかりません。しかし、それがたくさん呼ばれている場合は、それを最適化すると速度が大幅に向上する可能性があります。私は時間を実際に費やしている場所を見るためにプロファイラーの下にあなたのアプリを動かすだろう(私はJet Brainのドットトレースを個人的に好む)。 "GenerateDirtyPropertiesOnEntity"内で費やされた時間のパーセンテージは、メソッドを最適化することによって得られる理論上の最大パーフォレーションゲインを与えます。それが小さなパーセンテージになったら、そのままコードをそのまま残すことにします。私はこの速く作るの2つの簡単な方法を考えることができ

質問#2

  1. は手でプロパティの比較コードを記述します。
  2. 私はあなたが#1を行うにはしたくないと仮定しています比較コード

を生成するDynamicMethodクラスを使用します。 #2を1秒で表示するコードをいくつか掲載します。

アップデート:ここで

は、動的メソッド

class Util 
{ 
    public static Func<T,T, List<string>> CreateDitryChecker<T>() 
    { 
     var dm = 
      new DynamicMethod 
      (
       "$dirty_checker", 
       typeof(List<string>), 
       new[] { typeof(T), typeof(T) }, 
       typeof(T) 
      ); 

     var ilGen = dm.GetILGenerator(); 

     //var retVar = new List<string>(); 
     var retVar = ilGen.DeclareLocal(typeof(List<string>)); 
     ilGen.Emit(OpCodes.Newobj, typeof(List<string>).GetConstructor(new Type[0])); 
     ilGen.Emit(OpCodes.Stloc, retVar); 

     var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); 

     MethodInfo objEqualsMehtod = typeof(object).GetMethod("Equals", new[] { typeof(object) }); 
     MethodInfo listAddMethod = typeof(List<string>).GetMethod("Add"); 

     foreach (PropertyInfo prop in properties) 
     { 
      //Inject code equivalent to the following into the method: 

      //if (arg1.prop == null) 
      //{ 
      //  if (arg2.prop != null) 
      //  { 
      //   retVar.Add("prop") 
      //  } 
      //} 
      //else 
      //{ 
      // if (! arg1.prop.Equals(arg2)) 
      // { 
      //  retVar.Add("prop")  
      // } 
      //} 
      Label endLabel = ilGen.DefineLabel(); 
      Label elseLabel = ilGen.DefineLabel(); 

      //if arg1.prop != null, goto elseLabel 
      ilGen.Emit(OpCodes.Ldarg_0); 
      ilGen.Emit(OpCodes.Call, prop.GetGetMethod()); 
      ilGen.Emit(OpCodes.Brtrue, elseLabel); 

      //if arg2.prop != null, goto endLabel 
      ilGen.Emit(OpCodes.Ldarg_1); 
      ilGen.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); 
      ilGen.Emit(OpCodes.Brfalse, endLabel); 

      //retVar.Add("prop"); 
      ilGen.Emit(OpCodes.Ldloc, retVar); 
      ilGen.Emit(OpCodes.Ldstr, prop.Name); 
      ilGen.EmitCall(OpCodes.Callvirt, listAddMethod, null); 
      ilGen.Emit(OpCodes.Br, endLabel); 

      //elseLabel: 
      ilGen.MarkLabel(elseLabel); 

      //if (arg0.prop.Equals(arg1.prop), goto endLabel 
      ilGen.Emit(OpCodes.Ldarg_0); 
      ilGen.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); 
      ilGen.Emit(OpCodes.Ldarg_1); 
      ilGen.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); 
      ilGen.EmitCall(OpCodes.Callvirt, objEqualsMehtod, null); 
      ilGen.Emit(OpCodes.Brtrue, endLabel); 

      //retVar.Add("prop") 
      ilGen.Emit(OpCodes.Ldloc, retVar); 
      ilGen.Emit(OpCodes.Ldstr, prop.Name); 
      ilGen.EmitCall(OpCodes.Callvirt, listAddMethod, null); 

      //endLAbel: 
      ilGen.MarkLabel(endLabel); 
     } 

     ilGen.Emit(OpCodes.Ldloc, retVar); 
     ilGen.Emit(OpCodes.Ret); 


     return (Func<T, T, List<string>>) dm.CreateDelegate(typeof(Func<T, T, List<string>>)); 
    } 
} 

それはジェネリックパラメータTを取り込んを生成するためのコードだとのリストを返します2 Tのインスタンスを与え、デリゲートを返します。すべての変更されたプロパティ

パフォーマンスを向上させるには、メソッドを一度呼び出すだけで、その結果を読み取り専用静的フィールドに格納することをお勧めします。このような何かに動作します:

class FooBar 
{ 
    static readonly Func<FooBar,FooBar, List<string>> s_dirtyChecker; 

    static FooBar() 
    { 
     s_dirtyChecker = Util.CreateDirtyChecker<FooBar>(); 
    } 

    public List<string> GetDirtyProperties(Foobar other) 
    { 
     return s_dirtyChecker(this, other); 
    } 
} 
+0

ありがとうscott。彼はサンプルをコードすることを楽しみにしています。 – AlteredConcept

+0

デバッグするのに少し時間がかかります。約1分で投稿する必要があります 時 –

+0

問題ありません。時間をいただきありがとうございます! – AlteredConcept

3

あなたかもしれないはINotifyPropertyChangedインターフェイスを使って何かをしようとすることで、より良いパフォーマンスを得ます。反射を使用する代わりに、イベントベースのモデリングを使用して同じことを達成できます。

CSLA.NETは、そのアプローチをとるフレームワークの例です。

T SomeProperty() 
{ 
    get 
    { 
     return _someProperty; 
    } 
    set 
    { 
     if (_someProperty <> value) 
     { 
      _someProperty = value; 
      OnPropertyChanged("SomeProperty"); 
     } 
    } 
} 

、その後OnPropertyChangedを

OnPropertyChanged(object params) 
{ 
    DirtyProperties.Add(params); 
} 

ようになります、これは全空気コードである点に注意してください。私はparamsがどのように構築されたのか覚えていませんが、実際にはtypeオブジェクトではなく、DirtyPropertiesリストに追加するプロパティを決定する方法の名前が含まれています。

+0

ジョセフありがとう。私はこれを調べます。 – AlteredConcept

+0

問題ありません、幸せなコーディング! – Joseph

+1

+1偉大な心のために...これはまさに私が答えたものです。 –

関連する問題