2010-01-30 12 views
15

वहाँ एक तेज़ तरीका Func<TEntity, object>फन <T, T2> फन <T, object> पर फनक <T, T2> डालने का तेज़ तरीका?

public static class StaticAccessors<TEntity> 
{ 
public static Func<TEntity, TId> TypedGetPropertyFn<TId>(PropertyInfo pi) 
{ 
    var mi = pi.GetGetMethod(); 
    return (Func<TEntity, TId>)Delegate.CreateDelegate(typeof(Func<TEntity, TId>), mi); 
} 

public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi) 
{ 
    var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn"); 
    var genericMi = mi.MakeGenericMethod(pi.PropertyType); 
    var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi }); 

    //slow: lambda includes a reflection call 
    return x => typedGetPropertyFn.Method.Invoke(x, new object[] { }); //can we replace this? 
} 
} 

वहाँ एक रास्ता ऊपर के उदाहरण की तरह लौटे लैम्ब्डा में प्रतिबिंब कोड के बिना एक Func<TEntity, object> को typedGetPropertyFn कन्वर्ट करने के लिए है करने के लिए Fun<TEntity, TId> कास्ट करने के लिए है?

संपादित करें: जोड़ा संशोधित समाधान मुझे नीचे अग्रणी सही रास्ते जो मैं नीचे अंतिम समाधान में शामिल किया है के लिए 280Z28 को

ठीक है धन्यवाद। मैंने ऐसे प्लेटफ़ॉर्म के लिए प्रतिबिंब कोड छोड़ा है जो अभिव्यक्तियों का समर्थन नहीं करते हैं। प्लेटफ़ॉर्म के लिए जो 26x से 27x (13/.5 टिक औसत) पर int और string गुण प्राप्त करने के लिए बढ़ रहा है।

public static Func<TEntity, object> ValueUnTypedGetPropertyTypeFn(PropertyInfo pi) 
{ 
    var mi = typeof(StaticAccessors<TEntity>).GetMethod("TypedGetPropertyFn"); 
    var genericMi = mi.MakeGenericMethod(pi.PropertyType); 
    var typedGetPropertyFn = (Delegate)genericMi.Invoke(null, new[] { pi }); 

    #if NO_EXPRESSIONS 
    return x => typedGetPropertyFn.Method.Invoke(x, new object[] { }); 
    #else 
    var typedMi = typedGetPropertyFn.Method; 
    var obj = Expression.Parameter(typeof(object), "oFunc"); 
    var expr = Expression.Lambda<Func<TEntity, object>> (
      Expression.Convert(
       Expression.Call(
        Expression.Convert(obj, typedMi.DeclaringType), 
        typedMi 
       ), 
       typeof(object) 
      ), 
      obj 
     ); 
    return expr.Compile(); 
    #endif 
} 

उत्तर

6

आप जानते हैं, आप PropertyInfo.GetGetMethod() से एक MethodInfo प्राप्त कर सकते हैं। उस से, आप उस प्रॉपर्टी को पुनर्प्राप्त करने के लिए Func<object, object> प्राप्त करने के लिए निम्न का उपयोग कर सकते हैं। इसी तरह से, आप एक दृढ़ता से टाइप Func<TObject, TResult> वापस कर सकते हैं। किसी भी दिए गए MethodInfo के लिए, आपको इस कॉल के परिणामों को कैश करना चाहिए यदि आपको इसे एक से अधिक बार चाहिए क्योंकि यह विधि कम से कम परिमाण का आदेश परिणामी प्रतिनिधि को कॉल करने से अधिक महंगा है।

Func<Foo, Bar> typed = (f) => return new Bar(); 
Func<Foo, object> untyped = (f) => typed(f); 

इस तरह से आप बस प्रतिनिधि लपेट:

private static Func<object, object> BuildAccessor(MethodInfo method) 
{ 
    ParameterExpression obj = Expression.Parameter(typeof(object), "obj"); 

    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(); 
} 
5

.NET 4.0 में आप ऐसा कर सकते हैं क्योंकि Func प्रतिनिधि बाहरी संशोधक के साथ TResult को चिह्नित करता है। .NET 3.5 generic covariance/contravariance का समर्थन नहीं करता है, इसलिए आप आसानी से नहीं डाले जा सकते हैं। मुझे यकीन नहीं है कि ऐसा करने का एक और चालाक तरीका है जो प्रतिबिंब से तेज़ है।

यहां the .NET 4.0 doc page for Func है। ध्यान दें कि TResult को "आउट" के साथ चिह्नित किया गया है, इसलिए इसके वापसी मूल्य को कम-विशिष्ट प्रकार जैसे ऑब्जेक्ट के रूप में डाला जा सकता है।


एक त्वरित उदाहरण के लिए जिसमें कोई बाहरी निर्भरता नहीं है, निम्न कोड .NET 3.5 पर संकलित करने में विफल रहता है लेकिन .NET 4.0 पर संकलित और चलाता है।

// copy and paste into LINQpad 
void Main() 
{ 
    Func<int, string> func1 = GetString; 
    string res1 = func1(1); 
    res1.Dump(); 

    Func<int, object> func2 = func1; 
    object res2 = func2(1); 
    res2.Dump(); 
} 

public string GetString<T>(T obj) { 
    return obj.ToString(); 
} 
+0

क्या होगा यदि मेरा प्रारंभिक फ़ंक्शन गुड जैसे मूल्य प्रकार लौटाता है? तो मुझे Func पर डालने का प्रयास करते समय रनटाइम त्रुटि मिल रही है। –

5

आप निम्न कार्य विचार किया है।

+0

मैं ऐसा नहीं कर सकता क्योंकि मेरे पास 'बार' – mythz

+1

का संकलन-समय प्रकार नहीं है यदि आपके पास संकलन समय पर' बार 'प्रकार था, तो यह एक्सडी करने के लिए सबसे आसान और "ओलंपिक" तरीका होगा । –