C#反思:更新房产价值的最快方法?

这是使用reflection更新属性的最快方法吗? 假设该属性始终为int:

PropertyInfo counterPropertyInfo = GetProperty(); int value = (int)counterPropertyInfo.GetValue(this, null); counterPropertyInfo.SetValue(this, value + 1, null); 

请确保您以某种方式缓存PropertyInfo,以便您不能重复调用type.GetProperty。 除此之外,如果您为执行增量的类型的方法创建委托可能会更快,或者像Teoman建议使类型实现接口并使用它。

当你知道类型参数时,我在这里做了一些基准测试 (非generics方法不会非常不同)。 如果您无法直接访问属性, CreateDelegate将是属性的最快方法。 使用CreateDelegate您可以直接获得PropertyInfo GetGetMethodGetSetMethod ,因此每次都不会使用reflection。

 public static Func BuildGetAccessor(Expression> propertySelector) { return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate>(); } public static Action BuildSetAccessor(Expression> propertySelector) { return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate>(); } // a generic extension for CreateDelegate public static T CreateDelegate(this MethodInfo method) where T : class { return Delegate.CreateDelegate(typeof(T), method) as T; } public static PropertyInfo GetPropertyInfo(this Expression> propertySelector) { var body = propertySelector.Body as MemberExpression; if (body == null) throw new MissingMemberException("something went wrong"); return body.Member as PropertyInfo; } 

所以现在你打电话:

 TestClass cwp = new TestClass(); var access = BuildGetAccessor((TestClass t) => t.AnyValue); var result = access(cwp); 

或者更好的是,您可以将逻辑封装在专用类中,以便在其上具有get和set方法。

就像是:

 public class Accessor { public static Accessor Create(Expression> memberSelector) { return new GetterSetter(memberSelector); } public Accessor Get(Expression> memberSelector) { return Create(memberSelector); } public Accessor() { } class GetterSetter : Accessor { public GetterSetter(Expression> memberSelector) : base(memberSelector) { } } } public class Accessor : Accessor { Func Getter; Action Setter; public bool IsReadable { get; private set; } public bool IsWritable { get; private set; } public T this[S instance] { get { if (!IsReadable) throw new ArgumentException("Property get method not found."); return Getter(instance); } set { if (!IsWritable) throw new ArgumentException("Property set method not found."); Setter(instance, value); } } protected Accessor(Expression> memberSelector) //access not given to outside world { var prop = memberSelector.GetPropertyInfo(); IsReadable = prop.CanRead; IsWritable = prop.CanWrite; AssignDelegate(IsReadable, ref Getter, prop.GetGetMethod()); AssignDelegate(IsWritable, ref Setter, prop.GetSetMethod()); } void AssignDelegate(bool assignable, ref K assignee, MethodInfo assignor) where K : class { if (assignable) assignee = assignor.CreateDelegate(); } } 

简短而简单。 您可以为要获取/设置的每个“类属性”对携带此类的实例。

用法:

 Person p = new Person { Age = 23 }; var ageAccessor = Accessor(x => x.Age); int age = ageAccessor[p]; //gets 23 ageAccessor[p] = 45; //sets 45 

在这里使用索引器有点不好,你可以用专用的“Get”和“Set”方法替换它,但对我来说非常直观:)

为避免每次都要指定类型,

 var ageAccessor = Accessor(x => x.Age); var nameAccessor = Accessor(x => x.Name); var placeAccessor = Accessor(x => x.Place); 

我使基本的Accessor<>类可实现,这意味着你可以做到

 var personAccessor = new Accessor(); var ageAccessor = personAccessor.Get(x => x.Age); var nameAccessor = personAccessor.Get(x => x.Name); var placeAccessor = personAccessor.Get(x => x.Place); 

具有基本Accessor<>类意味着您可以将它们视为一种类型,例如,

 var personAccessor = new Accessor(); var personAccessorArray = new Accessor[] { personAccessor.Get(x => x.Age), personAccessor.Get(x => x.Name), personAccessor.Get(x => x.Place); }; 

你应该看看FastMember ( nuget , 源代码 ),它与reflection相比真的很快。

我测试了这3个实现:

  • PropertyInfo.SetValue
  • PropertyInfo.SetMethod
  • FastMember

基准测试需要基准function:

 static long Benchmark(Action action, int iterationCount, bool print = true) { GC.Collect(); var sw = new Stopwatch(); action(); // Execute once before sw.Start(); for (var i = 0; i <= iterationCount; i++) { action(); } sw.Stop(); if (print) System.Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds); return sw.ElapsedMilliseconds; } 

假类:

 public class ClassA { public string PropertyA { get; set; } } 

一些测试方法:

 private static void Set(string propertyName, string value) { var obj = new ClassA(); obj.PropertyA = value; } private static void FastMember(string propertyName, string value) { var obj = new ClassA(); var type = obj.GetType(); var accessors = TypeAccessor.Create(type); accessors[obj, "PropertyA"] = "PropertyValue"; } private static void SetValue(string propertyName, string value) { var obj = new ClassA(); var propertyInfo = obj.GetType().GetProperty(propertyName); propertyInfo.SetValue(obj, value); } private static void SetMethodInvoke(string propertyName, string value) { var obj = new ClassA(); var propertyInfo = obj.GetType().GetProperty(propertyName); propertyInfo.SetMethod.Invoke(obj, new object[] { value }); } 

脚本本身:

 var iterationCount = 100000; var propertyName = "PropertyA"; var value = "PropertyValue"; Benchmark(() => Set(propertyName, value), iterationCount); Benchmark(() => FastMember(propertyName, value), iterationCount); Benchmark(() => SetValue(propertyName, value), iterationCount); Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount); 

100 000次迭代的结果:

默认设置器:3ms

FastMember:36ms

PropertyInfo.SetValue:109ms

PropertyInfo.SetMethod:91ms

现在你可以选择你的!