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