2012-05-30 15 views
21

मुझे प्रतिबिंब का उपयोग करने में प्रदर्शन समस्याएं आ रही हैं।
तो मैं अपने वस्तुओं के गुणों के लिए प्रतिनिधियों को बनाने का फैसला किया और अब तक यह मिल गया:प्रतिबिंब प्रदर्शन - प्रतिनिधि बनाएं (गुण सी #)

TestClass cwp = new TestClass(); 
var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue"); 
var access = BuildGetAccessor(propertyInt.GetGetMethod()); 
var result = access(cwp); 
static Func<object, object> BuildGetAccessor(MethodInfo method) 
{ 
    var obj = Expression.Parameter(typeof(object), "o"); 

    Expression<Func<object, object>> expr = 
     Expression.Lambda<Func<object, object>>(
      Expression.Convert(
       Expression.Call(
        Expression.Convert(obj, method.DeclaringType), 
        method), 
       typeof(object)), 
      obj); 

    return expr.Compile(); 
} 

परिणाम अत्यधिक संतोषजनक, 30-40 के बारे में बार पारंपरिक विधि का उपयोग की तुलना में तेजी थे (PropertyInfo.GetValue (obj, null);)

समस्या यह है: मैं एक संपत्ति के SetValue कैसे बना सकता हूं, जो वैसे ही काम करता है? दुर्भाग्य से एक रास्ता नहीं मिला।

मैं ऐसा इसलिए कर रहा हूं क्योंकि मैं अपने आवेदन की संरचना के कारण <T> के साथ विधियों का उपयोग नहीं कर सकता।

+0

"मैं ऐसा इसलिए कर रहा हूं क्योंकि मैं अपने आवेदन की संरचना के कारण" < T > "के साथ विधियों का उपयोग नहीं कर सकता" - क्या इसका मतलब है कि आपका नेटफैक्स संस्करण <2.0? आप अपने आवेदन में जेनेरिक का उपयोग क्यों नहीं कर सकते? –

+0

इसके अलावा, आपकी संपत्तियों के प्रतिनिधियों को प्रतिबिंब के साथ क्या करना है, और प्रतिबिंब का उपयोग करके हल करने की क्या समस्या है? –

+0

प्रतिनिधियों के पास काफी बेहतर प्रदर्शन है और गतिशील रूप से उपयोग किया जा सकता है। जब आप गतिशील आमंत्रण का उपयोग करने की आवश्यकता होती है तो वे पसंदीदा विकल्प होते हैं। – GregRos

उत्तर

15

यह आप के लिए काम करना चाहिए:

static Action<object, object> BuildSetAccessor(MethodInfo method) 
{ 
    var obj = Expression.Parameter(typeof(object), "o"); 
    var value = Expression.Parameter(typeof(object)); 

    Expression<Action<object, object>> expr = 
     Expression.Lambda<Action<object, object>>(
      Expression.Call(
       Expression.Convert(obj, method.DeclaringType), 
       method, 
       Expression.Convert(value, method.GetParameters()[0].ParameterType)), 
      obj, 
      value); 

    return expr.Compile(); 
} 

उपयोग:

var accessor = BuildSetAccessor(typeof(TestClass).GetProperty("MyProperty").GetSetMethod()); 
var instance = new TestClass(); 
accessor(instance, "foo"); 
Console.WriteLine(instance.MyProperty); 

TestClass साथ

foo

2

गतिशील प्रकारों का उपयोग करें। वे हुड के नीचे प्रतिबिंब का उपयोग करते हैं, लेकिन वे बहुत तेज हैं।

अन्यथा ...

यहां नि: शुल्क तेजी से प्रतिबिंब पुस्तकालयों की टन अनुमोदक लाइसेंस के साथ वहाँ बाहर हैं। मैं आपको लिंक करूंगा, लेकिन बहुत सारे हैं, और मुझे यकीन नहीं है कि आपके अनुरूप कौन सा होगा। बस कोडप्लेक्स आदि खोजें। जब आपको कुछ पसंद आए, तो इसे आज़माएं।

लेकिन हाँ, शायद इससे पहले, सोचें कि प्रतिबिंब वास्तव में उत्तर है। अक्सर अन्य समाधान भी होते हैं।

संपादित करें: अनुरोध के रूप में ...

http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx
http://theburningmonk.com/2010/09/performance-test-dynamic-method-invocation-in-csharp-4/
http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

यह सामान्य ज्ञान जहाँ तक मैं बता सकता है। बाहर

public class TestClass 
{ 
    public string MyProperty { get; set; } 
} 

प्रिंटों:

+0

क्षमा करें? ऋणात्मक वोट क्यों? – GregRos

+1

डायनेमिक्स का प्रतिबिंब, आईएमओ के लिए उपयोग नहीं किया जाना चाहिए, जब तक ** कोई अन्य तरीका ** नहीं है। क्या आप कुछ डेटा पोस्ट कर सकते हैं जो समर्थन करता है * वे बहुत तेज़ हैं *? ... और ओपी अनुरोधों के तरीके में गतिशीलता का उपयोग करने का एक उदाहरण? ये नकारात्मक वोटों के कुछ कारण हो सकते हैं ... – IAbstract

+0

वह गतिशील आमंत्रण का उपयोग कर रहा है। जैसे सेटिंग विधियों, गुणों, आदि। यह ** बिल्कुल ** है जो आपको गतिशीलता के साथ करना है। – GregRos

10

मुझे लगता है कि यदि आप प्रदर्शन कुंजी है तो 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 लिखा था।

संबंधित मुद्दे