Tôi nghĩ bạn nên làm tốt hơn với CreateDelegate
xây dựng nếu hiệu suất là chìa khóa. Vì bạn biết chữ ký của phương thức trước, mà ở đây chỉ là GetGetMethod
và GetSetMethod
của PropertyInfo
, bạn có thể tạo đại biểu để thực thi phương thức rất trực tiếp với cùng một chữ ký. Các biểu thức sẽ phù hợp hơn nếu bạn cần xây dựng một số logic (mà bạn không có một phương thức xử lý) cho các đại biểu.Tôi đã làm một số điểm chuẩn trên các tuyến đường khác nhau cho vấn đề này:
Func<S, T> Getter;
Action<S, T> Setter;
PropertyInfo Property;
public void Initialize(Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
Property = body.Member as PropertyInfo;
//approaches:
//Getter = s => (T)Property.GetValue(s, null);
//Getter = memberSelector.Compile();
//ParameterExpression inst = Expression.Parameter(typeof(S));
//Getter = Expression.Lambda<Func<S, T>>(Expression.Property(inst, Property), inst).Compile();
//var inst = Expression.Parameter(typeof(S));
//Getter = Expression.Lambda<Func<S, T>>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile();
//Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), Property.GetGetMethod());
//Setter = (s, t) => Property.SetValue(s, t, null);
//var val = Expression.Parameter(typeof(T));
//var inst = Expression.Parameter(typeof(S));
//Setter = Expression.Lambda<Action<S, T>>(Expression.Call(inst, Property.GetSetMethod(), val),
// inst, val).Compile();
//Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), Property.GetSetMethod());
}
//Actual calls (tested under loop):
public T Get(S instance)
{
//direct invocation:
//return (T)Property.GetValue(instance, null);
//calling the delegate:
//return Getter(instance);
}
public void Set(S instance, T value)
{
//direct invocation:
//Property.SetValue(instance, value, null);
//calling the delegate:
//Setter(instance, value);
}
Kết quả cho khoảng 10000000 cuộc gọi - (Get, Set):
GetValue-SetValue (trực tiếp): 3800 ms, 5500 ms
GetValue-SetValue (đại biểu): 3600 ms, 5300 ms
biểu thức biên soạn:
Get: Expression.Property: 280 ms
Expression.Call: 280 ms
direct compile: 280 ms
Set: 300 ms
tạo đại biểu: 130 ms, 135 ms
trực tiếp cuộc gọi bất động sản: 70 ms, 70 ms
Tôi sẽ, trong trường hợp của bạn, viết:
public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}
public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}
// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
return Delegate.CreateDelegate(typeof(T), method) as T;
}
public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
return body.Member as PropertyInfo;
}
Vì vậy bây giờ bạn gọi:
TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);
Điều đó không đơn giản er ?? Đã viết một lớp chung here để xử lý điều chính xác.
"Tôi đang làm như vậy bởi vì tôi không thể sử dụng phương pháp với" < T > "do cấu trúc của ứng dụng của tôi" - Điều đó có nghĩa là phiên bản NETFX <2.0 của bạn? Tại sao bạn không thể sử dụng Generics trong ứng dụng của bạn? –
Ngoài ra, điều gì tạo ra các đại biểu cho các thuộc tính của bạn phải làm gì với sự phản chiếu, và bạn đang cố giải quyết vấn đề gì khi sử dụng sự phản chiếu? –
Đại biểu có hiệu suất tốt hơn rất nhiều và có thể được sử dụng động. Chúng là tùy chọn ưa thích khi bạn cần sử dụng lời gọi động. – GregRos