2013-02-05 20 views
8

पर जेनेरिक तर्क प्रकार और मान प्राप्त करें, आपको बंद/निर्मित जेनेरिक विधि में दिए गए तर्क मान को कैसे प्राप्त किया जाता है?जेनेरिक विधि

यह थोड़ी देर हो गया है क्योंकि मैंने प्रतिबिंब को छुआ नहीं है। यह सब मेरे पीछे, umm, जो भी हो, के पीछे होता था।

class Program 
{ 
    static void Main(string[] args) 
    { 
     new ConcreteFoo().GenericMethod<int>(5); 
     Console.ReadKey(); 
    } 
} 

class ConcreteFoo 
{ 
    public void GenericMethod<Q>(Q q) 
    { 
     var method = MethodInfo.GetCurrentMethod();  
     var parameters = method.GetParameters();  
     if (parameters.Length > 0) 
      foreach (var p in parameters) 
       Console.WriteLine("Type: {0}", p.ParameterType); 

     // That still prints Q as the type. 
     // I've tried GetGenericArguments as well. No luck.     
     // I want to know: 
     // 1) The closed type, i.e. the actual generic argument supplied by the caller; and 
     // 2) The value of that argument 
    } 

    public void GenericMethodWithNoGenericParameters<Q>() 
    { 
     // Same here 
    } 
} 

class GenericFoo<T> 
{ 
    public void NonGenericMethod(T t) { /* And here*/ } 
    public void GenericMethod<Q>(Q q) { /* And here */ } 
} 

अद्यतन

यह सवाल बेतुका और इसलिए प्रश्नकर्ता द्वारा बंद कर दिया है। वह सिर्फ अपने बच्चों को दिखाने के लिए इसे बनाए रखना चाहता है कि बेवकूफ पिताजी कैसे थे, अगर वे कभी सी # प्रोग्रामर बन गए।

+3

क्या कोई विशिष्ट कारण है कि आप 'q.GetType()' का उपयोग क्यों नहीं कर सकते? –

+5

'टाइपऑफ (क्यू)' आपको वर्तमान विधि के लिए रनटाइम आपूर्ति प्रकार देगा। यदि आप यही पूछ रहे हैं ... –

+6

बस उपर्युक्त टिप्पणियों के बीच अंतर को स्पष्ट करने के लिए: 'q.GetType() 'वस्तु का वास्तविक प्रकार प्राप्त करेगा जिसका अर्थ है कि यह उप-वर्ग या कार्यान्वयन हो सकता है (अगर 'क्यू 'एक इंटरफ़ेस था)। 'टाइपऑफ (क्यू)' विधि को कॉल करते समय उपयोग किए जाने वाले जेनेरिक प्रकार को वापस कर देगा (या तो स्पष्ट रूप से: 'जेनेरिकमैट (1) '(' क्यू'' ऑब्जेक्ट' है) या निहित रूप से: 'जेनेरिक विधि (1) '(' क्यू' 'Int32') इस प्रकार की परवाह किए बिना) –

उत्तर

8

संक्षिप्त उत्तर टाइपऑफ (क्यू) है।

विस्तृत उत्तर है (यही वजह है कि आप इन प्रकार की गणना नहीं कर सकते हैं और आप उन्हें विशेष रूप से लिखना चाहिए समझाने की कोशिश करता) इस प्रकार है:

प्रत्येक सामान्य विधि (जो अधिक सामान्य की तुलना में यह वर्ग की घोषणा कर रहा है) इसी गया है , "टेम्पलेट"/खुली विधि के लिए अपने सभी (कभी) स्पर्श किए गए विशिष्टताओं और अन्य विधिइन्फो के लिए अलग MethodInfo उदाहरण।

आप इस का उपयोग आप क्या चाहते प्राप्त करने के लिए कर सकते हैं:

class ConcreteFoo {  
    public void GenericMethod<Q>(Q q) { 
    var method = MethodInfo.GetCurrentMethod(); 
    var closedMethod = method.MakeGenericMethod(typeof(Q)); 

    // etc 
    } 
} 

कि क्यों है? ऐसा इसलिए है क्योंकि प्रतिबिंब में "गणना करने वाले संचालन" में से कोई भी कार्यप्रणाली वापस नहीं करता है जो बंद विशेषताओं को संदर्भित करता है।

आप स्थिर तरीकों तो जैसे ConcreteFoo द्वारा घोषित करके बताना हैं:

var atTime1 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); 

ConcreteFoo.GenericMethod(true); 

var atTime2 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); 

आप समान परिणाम मिलेंगे। जहां तक ​​जेनेरिक विधि और उसके विनिर्देशों का सहारा संबंधित है, आपको केवल जेनेरिक मोड (ओपन वेरिएंट) से जुड़े प्रतिबिंब वस्तु मिल जाएगी।

atTime2 में ताजा jitted GenericMethod < बूल> का जिक्र करते हुए एक अतिरिक्त MethodInfo नहीं होगा।

लेकिन यह वास्तव में एक बुरी बात नहीं है, है ना? GetMethods() को लगातार परिणाम लौटाएंगे और इसके परिणाम समय पर भिन्न नहीं होंगे। सामान्य तरीकों में से बीजगणित वास्तव में काफी अच्छा है जब यह आता है यह "नेविगेशन" आपरेशनों है के लिए है:

  1. सभी खुले MethodInfos IsGenericMethod = सच और IsGenericMethodDefinition = सच
  2. सभी बंद MethodInfos है IsGenericMethod सच है = और IsGenericMethodDefinition = झूठी
  3. एक बंद विधिइंफो पर .GetGenericMethodDefinition() को कॉल करके आप खुले एक
  4. कॉल करके कॉल कर सकते हैं।MakeGenericType एक खुला MethodInfo आपको मिल जो कुछ भी एक बंद कर दिया आप चाहते हैं पर (टाइप [] प्रकार के पैरामीटर) (उन प्रकार क्या हैं की वाक्य रचना के बारे में पता किया जा रहा बिना और जहां खंड का सम्मान नहीं करने के लिए एक अपवाद प्राप्त करने की संभावना के साथ)

MethodBase MethodInfo.GetCurrentMethod() 

और

StackTrace trace = new StackTrace(); 
IEnumerable<MethodBase> methods = from frame in trace.GetFrames() 
            select frame.GetMethod(); 
कभी नहीं

: एक ही प्रतिबिंब आपरेशन है कि मौजूदा धागा के नजरिए से आ के लिए (बजाय विधानसभाओं और प्रकार की है कि से) चला जाता है जेनेरिक तरीकों (यदि कोई हो) के वास्तविक बंद रूपों को वापस करें जो वास्तव में शीर्ष पर हैं, या वर्तमान कॉल स्टैक में हैं।

एक तरह से अपने प्रश्न बेतुका नहीं है, क्योंकि, जबकि के मामले GetCurrentMethod में आप आसानी से GetCurrentMethod प्लस MakeGenericMethod प्लस वाक्य रचना उपलब्ध typeof (जो कुछ भी) से बदलने सकता है, आप कर सकते हैं अपने कॉलर्स के बारे में मत कहो।

तो .. गैर-सामान्य तरीकों के लिए आप हमेशा अपने ढेर को देख सकते हैं और जान सकते हैं कि उन तरीकों के पैरामीटर प्रकार क्या हैं। विधियों ने एक दूसरे को बुलाया और अंत में आपका आह्वान किया गया ... लेकिन सामान्य लोगों के लिए (जो वास्तव में वास्तव में बंद हैं, क्योंकि मैं दोहराना चाहता हूं कि यह सोचने के लिए अजीब बात है कि एक सामान्य विधि जो दूसरे को चलाती है और कॉल करती है और किसी और द्वारा बुलाया जाता है (आदि)) एक खुला है) आप पैरामीटर के प्रकारों को नहीं ढूंढ सकते हैं जैसे आप किसी भी तरह के तरीकों के स्थानीय चर (जो निर्धारक हैं) के मूल्यों को नहीं सीख सकते हैं, लेकिन यह प्रदर्शन में एक बड़ी गड़बड़ी होगी संभावना)।

+0

मैंने अभी अभी यह जवाब देखा है। मैं अपने पिछले सवालों के जवाबों को रखने में बहुत अच्छा नहीं हूं। इस तरह के एक विस्तृत उत्तर के लिए बहुत बहुत धन्यवाद। मैं कल इसे पढ़ने जा रहा हूं और मैं हरे रंग की चेकी को अपना रास्ता देख सकता हूं। :-) –

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