मुझे लगता है कि यदि आप प्रदर्शन कुंजी है तो CreateDelegate
निर्माण के साथ बेहतर होगा। चूंकि आप पहले से विधि के हस्ताक्षर को जानते हैं, जो PropertyInfo
के GetGetMethod
और GetSetMethod
है, तो आप उसी हस्ताक्षर के साथ विधि को निष्पादित करने के लिए एक प्रतिनिधि बना सकते हैं। अभिव्यक्तियों को कुछ तर्क बनाने की आवश्यकता है (जिनके लिए आपके पास कोई विधि हैंडल नहीं है) प्रतिनिधियों को अभिव्यक्तियां बेहतर होंगी।मैं इस समस्या का अलग-अलग मार्गों पर कुछ बेंच मार्किंग किया: 10000000 के बारे में कॉल के लिए
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);
}
परिणाम - (जाओ, सेट):
getValue-setValue (प्रत्यक्ष): 3800 एमएस, 5500 एमएस
getValue-setValue (प्रतिनिधि): 3600 एमएस, 5300 एमएस
संकलित भाव:
Get: Expression.Property: 280 ms
Expression.Call: 280 ms
direct compile: 280 ms
Set: 300 ms
प्रतिनिधि बनाने के लिए: 130 एमएस, 135 एमएस
प्रत्यक्ष संपत्ति कॉल: 70 एमएस, 70 एमएस
मैं, आपके मामले में, लिखते थे:
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;
}
तो अब आप कॉल करते हैं:
TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);
क्या यह आसान नहीं है एर ?? सटीक चीज़ को संभालने के लिए एक सामान्य वर्ग here लिखा था।
"मैं ऐसा इसलिए कर रहा हूं क्योंकि मैं अपने आवेदन की संरचना के कारण" < T > "के साथ विधियों का उपयोग नहीं कर सकता" - क्या इसका मतलब है कि आपका नेटफैक्स संस्करण <2.0? आप अपने आवेदन में जेनेरिक का उपयोग क्यों नहीं कर सकते? –
इसके अलावा, आपकी संपत्तियों के प्रतिनिधियों को प्रतिबिंब के साथ क्या करना है, और प्रतिबिंब का उपयोग करके हल करने की क्या समस्या है? –
प्रतिनिधियों के पास काफी बेहतर प्रदर्शन है और गतिशील रूप से उपयोग किया जा सकता है। जब आप गतिशील आमंत्रण का उपयोग करने की आवश्यकता होती है तो वे पसंदीदा विकल्प होते हैं। – GregRos