2013-01-07 14 views
9

मेरे पास कुछ कोड है जो उत्पन्न प्रकार पर मिली सामान्य विधि के MethodInfo का उपयोग करता है। कुछ प्रतिबिंब से बचने के लिए, मेरे पास कोडएक टाइपबिल्डर जेनरेटिक methodinfo जेनेरिक विधि क्यों उत्पन्न करता है?

ldtoken Method 
ldtoken Type 
call GetMethodFromHandle(RuntimeMethodHandle,RunTimeTypeHandle) 

संकलन समय पर MethodInfos उत्पन्न करने के लिए पैटर्न का उपयोग करता है।

हालांकि, यदि methodInfo एक सामान्य प्रकार से संबंधित है और स्वयं एक सामान्य विधि है तो चीजें खराब हो जाती हैं। यहां कुछ कोड है जो केवल एक जीएम उत्पन्न करता है जो इसके methodInfo के खुले संस्करण को छोड़ देता है। अगर मैं इसे कहते से एक विशेष प्रकार मैं एक हैरान अपवाद ::

System.Reflection.MethodInfo GM[M]() पाने पर इसे बंद करने की कोशिश विधि को पुनः प्राप्त करने के लिए एक GenericMethodDefinition नहीं है। MakeGenericMethod को केवल उस विधि पर बुलाया जा सकता है जिसके लिए MethodBase.IsGenericMethodDefinition सत्य है।

यहाँ प्रासंगिक कोड ::

var aBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.RunAndSave); 
var mBuilder = aBuilder.DefineDynamicModule(aBuilder.GetName().Name, true); 
var typeBuilder = mBuilder.DefineType("NameSpace.Generic`1",TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.Public,typeof(object)); 
var TypeGenerics = typeBuilder.DefineGenericParameters(new[] { "T" }); 
var methodBuilder = typeBuilder.DefineMethod("GM", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig); 
var methodGenerics = methodBuilder.DefineGenericParameters(new[] { "M" }); 
methodBuilder.SetSignature(typeof(MethodInfo), null, null, Type.EmptyTypes, null, null); 
var ilgenerator = methodBuilder.GetILGenerator(); 
var typeBuilderClosedOverT = typeBuilder.MakeGenericType(TypeGenerics); 
ilgenerator.Emit(OpCodes.Ldtoken, methodBuilder); 
ilgenerator.Emit(OpCodes.Ldtoken, typeBuilderClosedOverT); 
ilgenerator.Emit(OpCodes.Call, 
    typeof(MethodBase).GetMethod(
     "GetMethodFromHandle", 
     BindingFlags.Public | BindingFlags.Static, 
     null, 
     new[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }, 
     null 
    ) 
); 
ilgenerator.Emit(OpCodes.Castclass,typeof(MethodInfo)); 
ilgenerator.Emit(OpCodes.Ret); 
var bakedType = typeBuilder.CreateType(); 
var methodInfo = bakedType.MakeGenericType(typeof(int)).GetMethod("GM").MakeGenericMethod(typeof(bool)).Invoke(null, null) as MethodInfo; 
var methodInfoClosedOverBool = methodInfo.MakeGenericMethod(typeof(bool)); 

यह केवल समय मेरी कोड शिकंजा ऊपर लगता है कि यह एक गैर सामान्य प्रकार पर एक genericmethod है है। यदि कोड फिर से लिखा जाता है ताकि सामान्य प्रकार पर सामान्य विधि, या सामान्य प्रकार पर सामान्य विधि, या सामान्य प्रकार पर सामान्य विधि यह सब काम करे। यह केवल उन दोनों का संयोजन है जो त्रुटियों का कारण बनता है। क्या मुझसे कुछ गलत हो रही है? https://connect.microsoft.com/VisualStudio/feedback/details/775989/clr-cannot-emit-a-token-for-an-open-generic-method-on-a-generic-type

+1

यह दिलचस्प है, ऐसा लगता है कि 'methodInfo.IsGenericMethodDefinition' वास्तव में' गलत 'है, हालांकि 'methodInfo.GetGenericArguments()' सामान्य पैरामीटर है जो एक प्रकार देता है। – svick

+0

हाँ यह निरीक्षण कर रहा है निश्चित रूप से यह सामान्य चीज़ की तरह दिखता है सामान्य है। मेरा वर्तमान समाधान यह सुनिश्चित करना है कि मेरे तरीकों के पास अद्वितीय नाम हैं और 'टाइप' और' स्ट्रिंग 'में गुज़र रहे हैं, और' type.GetMethod (...) 'को कॉल करना है, लेकिन मैं प्रतिबिंब से बचना चाहता हूं। –

+0

लगता है कि अब इसे .NET 4.7 –

उत्तर

3

, मेरे लिए एक CLR मुद्दे की तरह लग रहा है क्योंकि एक ही बात होता है अगर आप हाथ से आईएल लिखने और ilasm का उपयोग करें:

मैं इस मुद्दे के बारे एक बग प्रस्तुत की। यही कारण है, एक सामान्य वर्ग G और एक nongeneric वर्ग N, एक सामान्य विधि M के साथ प्रत्येक दिया जाता है तो nongeneric वर्ग से सामान्य विधि परिभाषा प्राप्त करने की कोशिश काम करता है:

ldtoken method void class N::M<[1]>() 
ldtoken class N<!T> 
call  class [mscorlib]System.Reflection.MethodBase [mscorlib] 
      System.Reflection.MethodBase::GetMethodFromHandle(
       valuetype [mscorlib]System.RuntimeMethodHandle, 
       valuetype [mscorlib]System.RuntimeTypeHandle) 
castclass [mscorlib]System.Reflection.MethodInfo 
ret 

लेकिन MethodInfo से लौटे सामान्य वर्ग के लिए एक सामान्य विधि परिभाषा नहीं है (लेकिन यह लगभग है, यह D.MakeGenericMethod(D.GetGenericArguments()) है जहां D विधि परिभाषा आप चाहते है):

ldtoken method void class G`1<!T>::M<[1]>() 
ldtoken class G`1<!T> 
call  class [mscorlib]System.Reflection.MethodBase [mscorlib] 
      System.Reflection.MethodBase::GetMethodFromHandle(
       valuetype [mscorlib]System.RuntimeMethodHandle, 
       valuetype [mscorlib]System.RuntimeTypeHandle) 
castclass [mscorlib]System.Reflection.MethodInfo 
ret 
+0

में हल किया गया है, धन्यवाद, वास्तव में मैंने वास्तव में ठोस प्रकारों के साथ एक ही चीज़ की है (सूची । कन्वर्टअल) और मैं इसे माइक्रोसॉफ्ट के लिए एक बग के रूप में रिपोर्ट करने जा रहा हूं। मुझे संदेह है कि बहुत कुछ होगा :( –

+0

दिलचस्प बात यह है कि इस आईएल को वापस संकलित नहीं किया जा सकता: "त्रुटि: टोकन पर वाक्यविन्यास त्रुटि '['" – IllidanS4

0

समस्या क्योंकि, की वजह से ldtoken method अनुदेश के भीतर निहित है सामान्य विधि परिभाषाओं को व्यक्त करने के लिए आईएल की अक्षमता, सीएलआर गलत विधि लोड करता है। निर्देश इस से ildasm द्वारा decompiled है:

ldtoken method class [mscorlib]System.Reflection.MethodInfo class NameSpace.Generic`1<!T>::GM<[1]>() 

जो भी मान्य आईएल नहीं है। सीएलआर फिर निर्देश को गड़बड़ कर देता है और इसके बजाय अपने सामान्य जेनेरिक पैरामीटर से जेनेरिक विधि तत्कालता लोड करता है।

DynamicMethod dyn = new DynamicMethod("", typeof(RuntimeMethodHandle), null); 
var il = dyn.GetILGenerator(); 
il.Emit(OpCodes.Ldtoken, typeof(GenClass<string>).GetMethod("GenMethod")); 
il.Emit(OpCodes.Ret); 
var handle = (RuntimeMethodHandle)dyn.Invoke(null, null); 
var m = MethodBase.GetMethodFromHandle(handle, typeof(GenClass<int>).TypeHandle); 

GetMethodFromHandle (जो भी केवल विधि संभाल, नहीं घोषित प्रकार की आवश्यकता होती है चाहिए) सिर्फ सेट की घोषणा:

var methodInfoClosedOverBool = (methodInfo.IsGenericMethodDefinition ? methodInfo : methodInfo.GetGenericMethodDefinition()).MakeGenericMethod(typeof(bool)); 

और अधिक परीक्षण के लिए, मैं एक ही मुद्दा दिखा एक छोटा कोड बनाया है प्रकार (नोटिस <int> या <string> कोई फर्क नहीं पड़ता) और कुछ भी गलत नहीं करता है।

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