2009-10-22 17 views
25

साथ निष्पादित मैं निम्नलिखित कोड:जेनेरिक विधि एक रनटाइम प्रकार

public class ClassExample 
{ 

    void DoSomthing<T>(string name, T value) 
    { 
     SendToDatabase(name, value); 
    } 

    public class ParameterType 
    { 
     public readonly string Name; 
     public readonly Type DisplayType; 
     public readonly string Value; 

     public ParameterType(string name, Type type, string value) 
     { 
      if (string.IsNullOrEmpty(name)) 
       throw new ArgumentNullException("name"); 
      if (type == null) 
       throw new ArgumentNullException("type"); 

      this.Name = name; 
      this.DisplayType = type; 
      this.Value = value; 
     } 
    } 

    public void GetTypes() 
    { 
     List<ParameterType> l = report.GetParameterTypes(); 

     foreach (ParameterType p in l) 
     { 
      DoSomthing<p.DisplayType>(p.Name, (p.DisplayType)p.Value); 
     } 

    } 
} 

अब, मैं जानता हूँ कि मैं नहीं कर सकता DoSomething() वहाँ इस सुविधा का उपयोग करने के लिए किसी भी अन्य तरीका है?

उत्तर

29

आप कर सकते हैं, लेकिन इसमें प्रतिबिंब शामिल है, लेकिन आप इसे कर सकते हैं।

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, p.Value }); 

यह युक्त वर्ग के शीर्ष पर दिखाई देगा, विधि की जानकारी पाने के लिए,, उचित प्रकार का एक सामान्य विधि बनाने तो आप उस पर आह्वान कॉल कर सकते हैं।

+0

बस एक पकड़, पी। वैल्यू एक स्ट्रिंग है इसलिए जब तक p.DisplayType टाइपफ (स्ट्रिंग) होने के लिए होता है तब तक चाल विफल हो जाएगी। – stevemegson

+1

शर्म की बात यह एकमात्र समाधान है, मेह –

+1

अच्छा, मुझे लगता है कि आप 4.0 में गतिशील उपयोग कर सकते हैं और यह सही जेनेरिक तर्क प्रकार का अनुमान लगाएगा, लेकिन मुझे अभी तक इसे सत्यापित करने का मौका नहीं मिला है। ऐसा नहीं है कि यह उपरोक्त कोड की तुलना में कवर के तहत कुछ भी अलग कर रहा है, लेकिन शायद यह है। –

5
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]{p.Name, p.Value}); 

काम करना चाहिए।

3

जेनिक्स प्रकार रनटाइम पर निर्दिष्ट नहीं किए जा सकते हैं जिस तरह से आप यहां चाहते हैं।

सबसे आसान विकल्प DoSomething का गैर-सामान्य अधिभार जोड़ना होगा, या बस DoSomething<object> पर कॉल करें और p.DisplayType को अनदेखा करें। जब तक SendToDatabaseसंकलन-समयvalue (और शायद यह नहीं होना चाहिए) पर निर्भर करता है, तो इसे object देने में कुछ भी गलत नहीं होना चाहिए।

यदि आप ऐसा नहीं कर सकते हैं, तो आपको प्रतिबिंब का उपयोग करके DoSomething पर कॉल करना होगा, और आप एक बड़ा प्रदर्शन हिट लेंगे।

1

कड़ाई से कह रहे हैं कि आप इसके लिए MethodInfo.MakeGenericMethod का उपयोग कर सकते हैं।

लेकिन मैं इसके बजाय गैर-सामान्य रूप से DoSomething को बदलने की अनुशंसा करता हूं, क्योंकि यह स्पष्ट नहीं है कि यह वास्तव में सामान्य होना चाहिए या नहीं।

+0

मैंने स्पष्टीकरण के लिए कार्यक्रम को सरल बना दिया। यह वास्तव में सबसे सुरुचिपूर्ण समाधान है, विश्वास करो या नहीं। :) धन्यवाद! – Sarit

3

पहले हम सही प्रकार के p.Value कन्वर्ट करने के लिए, के बाद से भले ही हम संकलन समय पर प्रकार जानते हैं कि हम सीधे विधि के लिए स्ट्रिंग पारित नहीं हो सकता

DoSomething<Int32>("10"); // Build error 

जरूरत है ... सरल अंकीय प्रकारों के लिए और दिनांक समय, हम उपयोग कर सकते हैं

object convertedValue = Convert.ChangeType(p.Value, p.DisplayType); 

अब हम आवश्यक सामान्य विधि आह्वान करने के लिए प्रतिबिंब का उपयोग कर सकते हैं ...

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, convertedValue }); 
संबंधित मुद्दे