2015-06-18 14 views
5

में केवल दूसरा तर्क प्रकार सेट करें मुझे निर्दिष्ट प्रकार के साथ संग्रह से फ़र्ट्स संपत्ति का चयन करने के लिए एक विधि बनाना है।जेनेरिक विधि

मैं इस तरह विधि बनाया है (मैं संक्षिप्तता के लिए कुछ भागों को हटा दिया है):

public static IQueryable<TResult> SelectFirstPropertyWithType<T, TResult>(this IQueryable<T> source) 
{ 
    // Get the first property which has the TResult type 
    var propertyName = typeof(T).GetProperties() 
     .Where(x => x.PropertyType == typeof(TResult)) 
     .Select(x => x.Name) 
     .FirstOrDefault(); 

    var parameter = Expression.Parameter(typeof(T)); 
    var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); 
    var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); 

    return source.Select(expression); 
} 

और मैं के रूप में इस विधि कॉल कर सकते हैं:

List<Person> personList = new List<Person>(); 

// .. initialize personList 

personList.AsQueryable() 
      .SelectFirstPropertyWithType<Person, int>() 
      .ToList(); 

सब कुछ ठीक काम करता है।

लेकिन, मैं पहले तर्क प्रकार को Person के रूप में सेट नहीं करना चाहता, क्योंकि संकलक इस तर्क प्रकार को संग्रह के स्रोत से अनुमानित कर सकता है। वहाँ किसी भी तरह से इस तरह विधि कॉल कर सकता:

.SelectFirstPropertyWithType<int>()

समस्या मैं अपने विधि के अंदर T पैरामीटर की आवश्यकता है, और मैं क्रम में प्रतिबिंब के साथ Func बनाने के लिए नहीं करना चाहती।

धन्यवाद।

+0

इस बारे में इसी तरह के कई सवाल था। जवाब बस है - आप ऐसा कुछ नहीं कर सकते हैं। कंपाइलर सभी प्रकार का अनुमान लगा सकता है या कोई भी –

उत्तर

2

सी # जेनिक्स बस आपको टाइप पैरामीटर का सबसेट निर्दिष्ट करने की अनुमति नहीं देता है। यह सब कुछ या कुछ भी नहीं है।

इसके आसपास काम करने का तरीका एक धाराप्रवाह इंटरफ़ेस लिखना है। आप इस ऑपरेशन को विधियों की एक श्रृंखला में तोड़ देते हैं।

public class FirstPropertyWithTypeSelector<T> 
{ 
    private readonly IQueryable<T> _source; 

    public FirstPropertyWithTypeSelector(IQueryable<T> source) 
    { 
     _source = source; 
    } 

    public IQueryable<TResult> OfType<TResult>() 
    { 
     // Get the first property which has the TResult type 
      var propertyName = typeof(T).GetProperties() 
      .Where(x => x.PropertyType == typeof(TResult)) 
      .Select(x => x.Name) 
      .FirstOrDefault(); 
     var parameter = Expression.Parameter(typeof(T)); 
     var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult)); 
      var expression = Expression.Lambda<Func<T, TResult>>(body, parameter); 
     return _source.Select(expression); 
    } 
} 

public static FirstPropertyWithTypeSelector<T> SelectFirstProperty(this IQueryable<T> source) 
{ 
    return new FirstPropertyWithTypeSelector<T>(source); 
} 

अब आप कॉल कर सकते हैं:

personList.AsQueryable() 
     .SelectFirstProperty().OfType<int>() 
     .ToList(); 
+0

क्या यह इकाई फ्रेमवर्क से 'IQueryable ' के कार्यान्वयन के साथ काम करेगा? – Dennis

+0

@ डेनिस - यह किसी भी ढांचे पर काम करना चाहिए जो IQueryable के कार्यान्वयन प्रदान करता है। –

+0

मुझे वास्तव में इस दृष्टिकोण को पसंद आया। लेकिन, आपको 'IQueryable ' को 'प्रथमप्रॉपर्टीविथ टाइप टाइपर ' –

3

नहीं। संकलक सभी प्रकार पैरामीटर का अनुमान लगाने में सक्षम होना चाहिए। यदि यह नहीं कर सकता है तो यह आपको उन सभी को निर्दिष्ट करने की मांग करेगा।

कंपाइलर आपको यह नहीं बता सकता कि यह पहले या दूसरे का अनुमान लगा सकता है, इसलिए एक गैर निर्धारक संकलन अनुप्रयोग होने की बजाय, यह बस टूट जाता है।

+0

उत्तर के लिए धन्यवाद। –

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