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
GetGetMethod
和GetSetMethod
,因此每次都不会使用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
现在你可以选择你的!