1

以下のコードでパフォーマンスを改善しようとしていますが、その方法はわかっていますが、どちらが最善のアプローチかはわかりません。最初のヒットには時間がかかりますが、その後のヒットはより速くなるはずです。ここで、T (T はクラス) をキャッシュし、キャッシュをチェックして "T" が存在するかどうかを確認します。存在する場合は、その関連情報 (NamedArguments) を取得し、NamedArguments のそれぞれを調べて、最後に基準が一致する場合は、先に進んで現在のプロパティの値を設定してください。

私はそれをより効率的かつパフォーマンス的にしたいだけです。何か案は?

var myProps = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(prop => Attribute.IsDefined(prop, typeof(MyCustomAttribute)) && prop.CanWrite && prop.GetSetMethod() != null);

foreach (var currentProperty in myProps)
{
    foreach (var currentAttributeForProperty in currentProperty.GetCustomAttributesData())
    {
        foreach (var currentNamedArgument in currentAttributeForProperty.NamedArguments)
        {
            if (string.Equals(currentNamedArgument.MemberInfo.Name, "PropName", StringComparison.OrdinalIgnoreCase))
            {
                currentAttribParamValue = currentNamedArgument.TypedValue.Value == null ? null : currentNamedArgument.TypedValue.Value.ToString();

                // read the reader for the currentAttribute value
                if (reader.DoesFieldExist(currentAttribParamValue))
                {
                    var dbRecordValue = reader[currentAttribParamValue] == DBNull.Value ? null : reader[currentAttribParamValue];

                    // set it in the property
                    currentProperty.SetValue(val, dbRecordValue, null);
                }
                break;
            }
        }
    }
}
4

4 に答える 4

4

DynamicMethodsまたはExpressionTreesは、リフレクションよりもはるかに高速になります。タイプのすべてのプロパティゲッター/セッターのキャッシュを作成し、その情報をタイプをキーとしてDictionary(または)にキャッシュすることができます。ConcurrentDictionary

フロー

  • タイプ情報を検出します(アプリの起動時など)。
  • 各プロパティの動的メソッドをコンパイルします(すべてのプロパティを一度に実行します)。
  • これらのメソッドをメタデータクラスに格納します(例を次に示します)。
  • メタデータをどこかにキャッシュします(アクセスが同期されている限り、静的フィールドでも問題ありません)。タイプをキーとして使用します。
  • 必要に応じて、タイプのメタデータを取得します。
  • 適切なゲッター/セッターを見つけます。
  • 呼び出し、実行したいインスタンスを渡します。

// Metadata for a type
public sealed class TypeMetadata<T> {

    // The compiled getters for the type; the property name is the key
    public Dictionary<string, Func<T, object>> Getters {
        get;
        set;
    }

    // The compiled setters for the type; the property name is the key
    public Dictionary<string, Action<T, object>> Setters {
        get;
        set;
    }
}

// rough invocation flow
var type = typeof( T);
var metadata = _cache[type];

var propertyName = "MyProperty";
var setter = metadata[propertyName];

var instance = new T();
var value = 12345;
setter( instance, value );

セッターの例

動的メソッドの実装からの抜粋(このテーマに関する優れた記事)。

この正確なコードが機能することを保証することはできませんが、私は非常によく似たコードを自分で作成しました。ILに慣れていない場合は、代わりに式ツリーを検討してください。

public static LateBoundPropertySet CreateSet(PropertyInfo property)
{
    var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(object), typeof(object) }, true);
    var gen = method.GetILGenerator();

    var sourceType = property.DeclaringType;
    var setter = property.GetSetMethod(true);

    gen.Emit(OpCodes.Ldarg_0); // Load input to stack
    gen.Emit(OpCodes.Castclass, sourceType); // Cast to source type
    gen.Emit(OpCodes.Ldarg_1); // Load value to stack
    gen.Emit(OpCodes.Unbox_Any, property.PropertyType); // Unbox the value to its proper value type
    gen.Emit(OpCodes.Callvirt, setter); // Call the setter method
    gen.Emit(OpCodes.Ret);

    var result = (LateBoundPropertySet)method.CreateDelegate(typeof(LateBoundPropertySet));

    return result;
}

*私の経験では25-100倍速い

于 2013-03-04T19:36:26.650 に答える
2

リフレクションはループで遅いことで有名なので、ある種のキャッシングがおそらく役立つでしょう。ただし、何をキャッシュするかを決定するには、を測定する必要があります。有名なことわざにあるように、「時期尚早の最適化はすべての悪の根源です」。本当に最適化する必要があり、正確に何を最適化する必要があるかを確認する必要があります。

より具体的なアドバイスとして、属性はコンパイル時に添付されるため、たとえば、型とそのpropertyInfoのリストをキャッシュできます。

于 2013-03-04T19:36:37.443 に答える
1

私もかつて同様の問題を抱えていました-反射は非常に遅いです。あなたが計画しているように、私はキャッシングを使用し、パフォーマンスは10倍以上に成長しました。これがパフォーマンスのボトルネックになることは二度とありませんでした。

于 2013-03-04T19:36:18.430 に答える
0

遭遇したタイプごとに「実行プラン」をキャッシュする前に、同様のロジックを作成しました。後続の実行では間違いなく高速でしたが、シナリオのプロファイルを作成して、コードの複雑さとメモリ使用量を追加する価値があるかどうかを確認する必要があります。

于 2013-03-04T19:33:35.370 に答える