Reflection related How much speed do I sacrifice?

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;
    }

How much can I sacrifice when using this? Does anyone know how best to do this?

Thank you in advance

+3
source share
4 answers

You ask 2 questions:

  • How much speed do you lose?
  • Is there a faster way to do this.

Question number 1:

: . , . , , . , . , , , . ( "Jet Brain Dot Trace" ), , . , "GenerateDirtyPropertiesOnEntity", , , . , .

№ 2

:

  • .
  • DynamicMethod

, # 1. , # 2 .

Update:

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 .

, readonly. - :

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);
   }
}
+3

, -, INotifyPropertyChanged. , , .

CSLA.NET , .

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

OnPropertyChanged

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

, . , , , , DirtyProperties.

+3

- , PostSharp, . .

+1

The only way to find out, no matter how much speed you donate, is to profile it.

In general, in my experience, thinking about properties, apparently, at best is about 1/50 of the speed of access to them directly. In the worst case, it can be 200 times slower. Depending on the frequency of this operation and the number of properties, this may or may not be a noticeable difference, although, again, that’s why I suggest profiling it to let you know if you need another solution.

+1
source

Source: https://habr.com/ru/post/1706690/


All Articles