दिलचस्प पोस्ट
क्या सूची <T> के संग्रह के आकार को प्रारंभ करने के लिए उपयुक्त है यदि यह आकार उचित रूप से ज्ञात है? डेटा-आईडी विशेषता कैसे प्राप्त करें? क्यों InputStream # read () इंटर्न नहीं है और बाइट नहीं है? त्रुटि 2006 (HY000): MySQL सर्वर दूर चला गया है कैमरा एसडीके के साथ कैमरे तक पहुंचें जावा गतिशील सरणी आकार? इंटरफ़ेस या अमूर्त वर्ग? जावास्क्रिप्ट में एकाधिक चर की घोषणा बाह्यरेखा त्रिज्या? MySQL – कॉलम के लिए पंक्तियाँ आईओएस 6 में एटोरोटेशन के लिए एप्लिकेशन को पूरी तरह से सही तरीके से कैसे काम करना है? Xcode 7 में ENABLE_BITCODE क्या करता है? अजगर में उड़ने पर वैरिएबल नाम पैदा करना नवीनतम संशोधित फाइल को लगातार निर्देशिका में कैसे खोजें? किसी भी तरह से मुख्य डेटा को पॉप्युलेट करने के लिए?

सामान्य विधि के लिए GetMethod

मैं किस तरह के गणनीय प्रकार की विधि के लिए MethodInfo को पुनः प्राप्त करने की कोशिश कर रहा हूं:

typeof (Enumerable).GetMethod("Where", new Type[] { typeof(IEnumerable<>), typeof(Func<,>) }) 

लेकिन रिक्त हो जाओ मैं क्या गलत कर रहा हूं?

वेब के समाधान से एकत्रित समाधान "सामान्य विधि के लिए GetMethod"

यह पिछले उत्तर कुछ मामलों में काम करता है, हालांकि:

  • यह नेस्टेड जेनेरिक प्रकारों को संभाल नहीं करता, जैसे कि एक पैरामीटर प्रकार का Action<IEnumerable<T>> । यह सभी Action<> मैचों के रूप में प्रयोग करेगा, उदाहरण के लिए, string.Concat(IEnumerable<string>) और string.Concat(IEnumerable<string>) string.Concat<T>(IEnumerable<T>) दोनों मैच होगा यदि "Concat" खोज के साथ प्रकार IEnumerable<> पर स्ट्रिंग प्रकार क्या वास्तव में वांछनीय है नेस्टेड जेनेरिक प्रकारों को संचरित कर रहा है, जबकि सभी जेनेरिक मापदंडों का इलाज करते हुए प्रत्येक दूसरे के नाम से मेल खाते हैं, जबकि कंक्रीट प्रकार से मेल नहीं खाते।
  • यह एक अपवाद फेंकने के बजाय पहली पद्धति का मिलान करता है, यदि परिणाम अस्पष्ट है, जैसे कि type.GetMethod() करता है। इसलिए, यदि आप भाग्यशाली हो, या आप शायद नहीं चाहते हैं तो आपको वह विधि मिल सकती है
  • कभी-कभी यह अनिवार्यता से बचने के लिए BindingFlags को निर्दिष्ट करने के लिए आवश्यक होगा, जैसे जब कोई व्युत्पन्न क्लास विधि 'बेस को छिपाता है' आधार वर्ग विधि आप सामान्य रूप से बेस क्लास के तरीकों को ढूंढना चाहते हैं, लेकिन किसी विशेष मामले में नहीं, जहां आप जानते हैं कि जिस विधि का आप खोज रहे हैं वह व्युत्पन्न वर्ग में है। या, आप शायद जानते हो कि आप एक स्थैतिक बनाम उदाहरण पद्धति, सार्वजनिक बनाम निजी आदि की तलाश कर रहे हैं और यदि यह सटीक नहीं है तो मैच नहीं करना चाहते हैं।
  • यह type.GetMethods() साथ एक अन्य प्रमुख गलती को type.GetMethods() नहीं करता है, जिसमें वह इंटरफ़ेस प्रकार पर एक विधि की खोज करते समय तरीकों के लिए आधार इंटरफेस भी खोज नहीं करता है। ठीक है, हो सकता है कि यह पिक किया जा रहा हो, लेकिन यह GetMethods() में एक और प्रमुख दोष है जो मेरे लिए एक समस्या रही है
  • कॉलिंग type.GetMethods() अक्षम है, type.GetMember(name, MemberTypes.Method, ...) प्रकार। विधि type.GetMember(name, MemberTypes.Method, ...) प्रकार में सभी विधियों के बजाय केवल एक मिलान नाम के तरीकों को वापस करेगा।
  • एक अंतिम नीट-पिक के रूप में, GetGenericMethod() नाम गुमराह करने वाला हो सकता है, क्योंकि आप सामान्य GetGenericMethod() प्रकार के कारण किसी गैर-सामान्य विधि का पता लगाने की कोशिश कर रहे हैं, जो किसी पैरामीटर प्रकार में किसी प्रकार का पैरामीटर हो सकता है।

यहां एक ऐसा संस्करण है जो उन सब बातों को पूरा करता है, और त्रुटिपूर्ण GetMethod() लिए सामान्य प्रयोजन के प्रतिस्थापन के रूप में उपयोग किया जा सकता है। ध्यान दें कि दो विस्तार विधियां प्रदान की जाती हैं, एक बाइंडफ्लैग के साथ और एक (सुविधा के लिए) बिना।

 /// <summary> /// Search for a method by name and parameter types. /// Unlike GetMethod(), does 'loose' matching on generic /// parameter types, and searches base interfaces. /// </summary> /// <exception cref="AmbiguousMatchException"/> public static MethodInfo GetMethodExt( this Type thisType, string name, params Type[] parameterTypes) { return GetMethodExt(thisType, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, parameterTypes); } /// <summary> /// Search for a method by name, parameter types, and binding flags. /// Unlike GetMethod(), does 'loose' matching on generic /// parameter types, and searches base interfaces. /// </summary> /// <exception cref="AmbiguousMatchException"/> public static MethodInfo GetMethodExt( this Type thisType, string name, BindingFlags bindingFlags, params Type[] parameterTypes) { MethodInfo matchingMethod = null; // Check all methods with the specified name, including in base classes GetMethodExt(ref matchingMethod, thisType, name, bindingFlags, parameterTypes); // If we're searching an interface, we have to manually search base interfaces if (matchingMethod == null && thisType.IsInterface) { foreach (Type interfaceType in thisType.GetInterfaces()) GetMethodExt(ref matchingMethod, interfaceType, name, bindingFlags, parameterTypes); } return matchingMethod; } private static void GetMethodExt( ref MethodInfo matchingMethod, Type type, string name, BindingFlags bindingFlags, params Type[] parameterTypes) { // Check all methods with the specified name, including in base classes foreach (MethodInfo methodInfo in type.GetMember(name, MemberTypes.Method, bindingFlags)) { // Check that the parameter counts and types match, // with 'loose' matching on generic parameters ParameterInfo[] parameterInfos = methodInfo.GetParameters(); if (parameterInfos.Length == parameterTypes.Length) { int i = 0; for (; i < parameterInfos.Length; ++i) { if (!parameterInfos[i].ParameterType .IsSimilarType(parameterTypes[i])) break; } if (i == parameterInfos.Length) { if (matchingMethod == null) matchingMethod = methodInfo; else throw new AmbiguousMatchException( "More than one matching method found!"); } } } } /// <summary> /// Special type used to match any generic parameter type in GetMethodExt(). /// </summary> public class T { } /// <summary> /// Determines if the two types are either identical, or are both generic /// parameters or generic types with generic parameters in the same /// locations (generic parameters match any other generic paramter, /// but NOT concrete types). /// </summary> private static bool IsSimilarType(this Type thisType, Type type) { // Ignore any 'ref' types if (thisType.IsByRef) thisType = thisType.GetElementType(); if (type.IsByRef) type = type.GetElementType(); // Handle array types if (thisType.IsArray && type.IsArray) return thisType.GetElementType().IsSimilarType(type.GetElementType()); // If the types are identical, or they're both generic parameters // or the special 'T' type, treat as a match if (thisType == type || ((thisType.IsGenericParameter || thisType == typeof(T)) && (type.IsGenericParameter || type == typeof(T)))) return true; // Handle any generic arguments if (thisType.IsGenericType && type.IsGenericType) { Type[] thisArguments = thisType.GetGenericArguments(); Type[] arguments = type.GetGenericArguments(); if (thisArguments.Length == arguments.Length) { for (int i = 0; i < thisArguments.Length; ++i) { if (!thisArguments[i].IsSimilarType(arguments[i])) return false; } return true; } } return false; } 

ध्यान दें कि IsSimilarType(Type) विस्तार विधि को सार्वजनिक किया जा सकता है और यह स्वयं के लिए उपयोगी हो सकता है। मुझे पता है, नाम बहुत अच्छा नहीं है – आप एक बेहतर के साथ आने के लिए स्वागत है, लेकिन यह वाकई समझने में बहुत लंबा हो सकता है कि यह क्या करता है। इसके अलावा, मैंने 'रेफरी' और सरणी प्रकारों के लिए जाँच करके एक और सुधार जोड़ा है (मिलान के लिए रेफरी को अनदेखा कर दिया गया है, लेकिन सरणियों का आयाम होना चाहिए)।

तो, इस तरह से माइक्रोसॉफ्ट इसे कैसे करना चाहिए था यह वाकई मुश्किल नहीं है

हाँ, मुझे पता है, आप लिनक का उपयोग करते हुए कुछ तर्क को कम कर सकते हैं, लेकिन मैं इस तरह कम-स्तरीय दिनचर्या में लिनक का एक बहुत बड़ा प्रशंसक नहीं हूं, और जब तक कि Linq मूल कोड के रूप में अनुसरण करना आसान नहीं है, जो अक्सर मामला नहीं है, आईएमओ

यदि आप IsSimilarType() प्यार करते हैं, और आपको चाहिए, तो आप इसके साथ IsSimilarType() के भीतरी भाग को बदल सकते हैं (1 में 8 लाइनें बदल जाती हैं):

 if (thisArguments.Length == arguments.Length) return !thisArguments.Where((t, i) => !t.IsSimilarType(arguments[i])).Any(); 

एक आखिरी चीज: यदि आप जेनेरिक पैरामीटर के साथ एक सामान्य पैरामीटर की तलाश कर रहे हैं, जैसे कि Method<T>(T, T[]) , तो आपको एक प्रकार का पता लगाना होगा जो सामान्य पैरामीटर है ( IsGenericParameter == true ) पैरामीटर प्रकार के लिए पास करने के लिए ('वाइल्डकार्ड' मेलिंग के कारण कोई भी होगा) हालांकि, आप बस new Type() नहीं कर सकते हैं – आपको वास्तविक खोजना होगा (या टाइपबिल्डर के साथ एक का निर्माण) इसे आसान बनाने के लिए, मैंने public class T घोषणा को जोड़ा, और इसके लिए जाँच करने के लिए और किसी भी सामान्य पैरामीटर से मेल खाने वाले IsSimilarType() तर्क जोड़ा। यदि आपको एक T[] की ज़रूरत है, तो बस T.MakeArrayType(1) उपयोग करें।

दुर्भाग्यवश, जेनेरिक्स अच्छी तरह से समर्थित नहीं हैं। NET प्रतिबिंब में। इस विशेष मामले में, आपको GetMethods को कॉल करना होगा और फिर उस विधि के लिए परिणाम सेट को फ़िल्टर करना होगा जिसे आप ढूंढ रहे हैं। निम्नलिखित की तरह एक विस्तार विधि चाल करना चाहिए

 public static class TypeExtensions { private class SimpleTypeComparer : IEqualityComparer<Type> { public bool Equals(Type x, Type y) { return x.Assembly == y.Assembly && x.Namespace == y.Namespace && x.Name == y.Name; } public int GetHashCode(Type obj) { throw new NotImplementedException(); } } public static MethodInfo GetGenericMethod(this Type type, string name, Type[] parameterTypes) { var methods = type.GetMethods(); foreach (var method in methods.Where(m => m.Name == name)) { var methodParameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); if (methodParameterTypes.SequenceEqual(parameterTypes, new SimpleTypeComparer())) { return method; } } return null; } } 

इसके साथ में निम्नलिखित कोड काम करेगा:

 typeof(Enumerable).GetGenericMethod("Where", new Type[] { typeof(IEnumerable<>), typeof(Func<,>) });