2016-05-05 11 views
0

私は以下の "計算"クラスを持っています。この例では"計算"クラスの変更を効率的にチェックする方法

public class Foo 
{ 

    private int? _sum = 0; 

    public int Sum 
    { 
     get 
     { 
      if (_sum == null) 
       _sum = 1 + 1; //simple code to show "some" calculation happens... 

      return _sum.GetValueOrDefault(); 
     } 
    } 

} 

のみ1フィールド/メンバーがありますが、私の実際のクラスでは、すべてがちょうど別の値の計算と似ていること、50人が周りにあります。

クラスでは、Recalcメソッドもあります。古い値がnewvalues異なる場合

は、この再計算の方法は、4つの物事

  1. 保存
  2. をnullにすべてのフィールドを設定し、古い値
  3. は、すべてのメンバー
  4. 小切手のゲッターを呼び出しず、関連するものを実行する

古い値を保存して変更を確認するにはどうすればよいのでしょうか新しい値。

私の現在の実装では、このです:

public string GetValuesKey() 
{ 
    //again this method only handles the 1 Member and not all 50 in real app its string.Format("{0}|{1}|{2}|...{49}|{50}|", ....); 
    return string.Format("{0}|", this.Sum); 
} 

public void Recalc() 
{ 
    var oldValues = GetValuesKey(); 

    //set all fields to null 
    //call the getters 

    var newValues = GetValuesKey(); 
    if (oldValues != newValues) 
    { 
     //something changed... 
    } 
} 

しかし、私は参照型(文字列)に構造体(10進数)書き込みでボクシングをやっているので、このコードでメモリ/パフォーマンスの問題があります。

私は、すべてのメンバーに対して50個の追加フィールド(_oldSumなど)をしないようにしたいと考えています。 Recalc処理中にメンバーが変更されたかどうかを確認するだけです。

ちょうどケースでは、私は次のコードを行うことができません。

public void Recalc() 
{ 
    var changes = false; 

    var oldValue = this.Sum; 
    _sum = null; 
    var newValue = this.Sum; 
    if (oldValue != newValue) 
     changes = true; 

    //check next member 
    oldValue = this.Sum2; 
    _sum2 = null; 
    newValue = this.Sum2; 
    if (oldValue != newValue) 
     changes = true; 

    //check next member and so on... 
} 

私が最初にnullにすべてのフィールドを設定する必要があるとだけ、それらのすべてNULLの後に設定されているので、合計メンバーが凝集するかどうメンバーがexmpleのための相互に依存しているので、私は、ゲッターを実行することができます他の2つのメンバーで、最初はnullに設定されていますが、まだ古い値が残っています。

フィールドの値を設定する前にすべての値を表すものを保存し、メンバのゲッタを呼び出して変更をチェックする方法が必要です。

助けを歓迎します。

編集:ここでは

はコードで、私はテストのパフォーマンス/メモリに書きました: http://pastebin.com/3WiNJHyS

+0

私は数ヶ月前に公開したこのプロジェクトをチェックしてください:http://matiasfidemraizer.com/trackerdog –

+0

リフレクションはあなたのためのオプションではありません?そうでない場合 - なぜですか? – Evk

+0

@Evkこのクラスが作成されるのは736.200(むしろ大規模な場合 - 通常は1000-10000のような)時間ですが、各クラスには50人のメンバーがいますが、リフレクションはオプションではないので、これらの数値は遅くなります。 MK87のような辞書は作成しませんでしたが、 "oldvalues"のプロパティ名/値を格納する構造体を持つリストがありました。 Value1 + Value2 - (Value 3 + Value4)/ Value5(Simplified)のような変更をチェックするために使用できる計算があることを期待しました。変化する。 –

答えて

1

文字列内のすべての値を結合し、すべての値をarray(decimal)に入れ、すべてのフィールドをnullに設定して計算を行い、古い値と新しい値の配列を比較します。

1

あなたが自分ですべて50個の_oldValueフィールドを書きたくない場合は、唯一の選択肢であります反射を使用するには、いくつかのボクシング/アンボクシングを意味するので、パフォーマンスは最善のものではありません。

とにかく、次の実装では、Fooクラスで計算に関係するメンバーがすべて、タイプがdecimal?のプロパティであると仮定します。 それ以外の場合は、関連するすべてのフィールド/プロパティにBindingFlagsおよび/またはAttributeというもっと複雑な解決策が必要です。

public void Recalc() 
{ 
    var propertyInfos = GetType() 
     .GetProperties() 
     .Where(pInfo => pInfo.PropertyType.IsValueType); 

    var fieldInfos = GetType() 
     .GetFields() 
     .Where(fInfo => fInfo.FieldType.IsValueType); 

    //create a dictionary with all the old values 
    //obtained from the backing fields. 
    var oldValueDictionary = fieldInfos.ToDictionary(
     fInfo => fInfo.Name, 
     fInfo => (decimal?)fInfo.GetValue(this)); 

    //set all properties to null 
    foreach (var pInfo in propertyInfos) 
     pInfo.SetValue(this, null); 

    //call all the getters to calculate the new values 
    foreach (var pInfo in propertyInfos) 
     pInfo.GetValue(this); 

    //compare new field values with the old ones stored in the dictionary; 
    //if only one different is found, the if is entered. 
    if (fieldInfos.Any(fInfo => 
     (decimal?)fInfo.GetValue(this) != oldValueDictionary[fInfo.Name])) 
    { 
     //do stuffs 
    } 
} 

最終的に、クラス構成は非常に奇妙です。ゲッターのすべての計算を設定するのが最善の選択でしょうか?多分あなたはあなたのデザインについて考え直すべきでしょう。 1つのタスクは、プロパティ値(ゲッタ)を取得することです。別のタスクは、(バッキングフィールドに格納された値から開始して)何かを計算することです...

関連する問題