सी # का उपयोग करें। सामान्य पैरामीटर के रूप में टाइप करें


89

मेरे पास प्रकारों की एक सूची है (System.Type) जिसे डेटाबेस में टी की आवश्यकता है।

इस प्रकार के प्रत्येक के लिए, मुझे निम्नलिखित एक्सटेंशनमेथोड को कॉल करने की आवश्यकता है (जो LinqToNhibernate का हिस्सा है):

Session.Linq<MyType>()

हालाँकि मेरे पास MyType नहीं है, लेकिन मैं इसके बजाय एक प्रकार का उपयोग करना चाहता हूं।

मेरे पास क्या है:

System.Type typeOne;

लेकिन मैं निम्नलिखित प्रदर्शन नहीं कर सकता:

Session.Linq<typeOne>()

मैं जेनेरिक पैरामीटर के रूप में एक प्रकार का उपयोग कैसे कर सकता हूं?

जवाबों:


95

आप सीधे नहीं कर सकते। जेनरिक का उद्देश्य संकलन-समय प्रकार की सुरक्षा प्रदान करना है , जहां आप जानते हैं कि आप उस प्रकार को जानते हैं जो आप संकलन-समय में रुचि रखते हैं, और उस प्रकार के उदाहरणों के साथ काम कर सकते हैं। आपके मामले में, आप केवल Typeइतना ही जानते हैं कि आप किसी भी संकलन-समय की जांच नहीं कर सकते हैं कि आपके पास जो भी वस्तुएं हैं वे उस प्रकार के उदाहरण हैं।

आपको प्रतिबिंब के माध्यम से विधि को कॉल करना होगा - कुछ इस तरह से:

// Get the generic type definition
MethodInfo method = typeof(Session).GetMethod("Linq", 
                                BindingFlags.Public | BindingFlags.Static);

// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeOne);
// The "null" is because it's a static method
method.Invoke(null, arguments);

यदि आपको इस प्रकार का उपयोग करने की आवश्यकता है, तो आपको अपनी स्वयं की जेनेरिक विधि लिखने में अधिक सुविधाजनक लग सकता है, जो भी अन्य जेनेरिक विधियों की आवश्यकता है, और फिर प्रतिबिंब के साथ अपनी विधि को कॉल करें


1
मैं एक समाधान के बारे में पढ़ता हूं जो विधि को कॉल करने के लिए प्रतिबिंब का उपयोग करता है। लेकिन मुझे उम्मीद थी कि एक और समाधान था।
जन

आह्वान विधि एक "वस्तु" लौटाती है। मैं इस ऑब्जेक्ट पर क्वेरी नहीं कर पा रहा हूँ जब तक मैं इसे सही प्रकार पर नहीं डाल देता। (जो शायद IQueryable <T> होगा)। मेरे पास जो टाइप है, मैं ऑब्जेक्ट को कैसे कर सकता हूं?
जनवरी

3
@ जान: आप नहीं कर सकते - लेकिन तब आप उस प्रकार का उपयोग नहीं कर पाएंगे, क्योंकि आप संकलन-समय पर प्रकार नहीं जानते हैं ... यह वह जगह है जहाँ आप एक सामान्य विधि लिखने के लायक हो सकते हैं जो सब कुछ आप एक जोरदार टाइप तरह से चाहते हैं, और बुला करता है कि प्रतिबिंब के साथ। वैकल्पिक रूप से, गैर-जेनेरिक IQueryableआपको क्या चाहिए?
जॉन स्कीट

2
@ जॉन: धन्यवाद, मैं अपना स्वयं का सामान्य तरीका लिखने की कोशिश करूंगा। दुर्भाग्य से गैर-सामान्य Iqueryable समस्या का समाधान नहीं करेगा।
जनवरी

1
@Jon: किसी अन्य सामान्य विधि को कॉल करने के लिए मेरे स्वयं के सामान्य तरीके का उपयोग करके समस्या का समाधान किया गया
Jan

30

ऐसा करने के लिए आपको प्रतिबिंब का उपयोग करने की आवश्यकता है:

typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);

(यह मानते हुए कि Linq<T>()यह एक स्थिर विधि है Session)

यदि Sessionवास्तव में एक वस्तु है , तो आपको यह जानना होगा कि Linqविधि वास्तव में कहां घोषित की गई है, और Sessionएक तर्क के रूप में पास करें :

typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
     .Invoke(null, new object[] {Session});

1

मेरे पास एक सामान्य विधि है जो कॉल जेनेरिक विधि को प्रतिबिंब के माध्यम से बुलाती है

/// <summary>
    /// This method call your method through Reflection 
    /// so i wil call the method like CallGenericMethodThroughReflection<Session>(assemblyQualifiedName,Linq,false,new[] { file }) 
    /// </summary>
    /// <typeparam name="T">Call method from which file</typeparam>
    /// <param name="assemblyQualifiedName">Your can get assemblyQualifiedName like typeof(Payroll.Domain.Attendance.AttendanceApplicationMaster).AssemblyQualifiedName</param>
    /// <param name="methodName"></param>
    /// <param name="isStaticMethod"></param>
    /// <param name="paramaterList"></param>
    /// <param name="parameterType">pass parameter type list in case of the given method have overload  </param>
    /// <returns>return object of calling method</returns>
    public static object CallGenericMethodThroughReflection<T>(string assemblyQualifiedName, string methodName,bool isStaticMethod ,object[] paramaterList,Type[] parameterType = null)
    {
        try
        {
            object instance = null;
            var bindingAttr = BindingFlags.Static | BindingFlags.Public;
            if (!isStaticMethod)
            {
                instance = Activator.CreateInstance<T>();
                bindingAttr = BindingFlags.Instance | BindingFlags.Public;
            }
            MethodInfo MI = null;
            var type = Type.GetType(assemblyQualifiedName);
            if(parameterType == null)
                MI = typeof(T).GetMethod(methodName, bindingAttr);
            else
                MI = typeof(T).GetMethod(methodName, bindingAttr,null, parameterType, null);//this will work in most case some case not work
            if (type == null || MI == null) // if the condition is true it means given method or AssemblyQualifiedName entity not found
                return null;
            var genericMethod = MI.MakeGenericMethod(new[] { type });
            return genericMethod.Invoke(instance, paramaterList);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.