c# - एक प्रकार तर्क के साथ जेनेरिक विधि को कॉल करना केवल निष्पादन समय पर ज्ञात




linq generics reflection (2)

संपादित करें: ठीक है, एक छोटा लेकिन पूरा कार्यक्रम के लिए समय। मूल उत्तर पहले जैसा है:

  • Type.GetMethod के साथ "खुली" जेनेरिक विधि पाएं
  • MakeGenericMethod का उपयोग करके इसे सामान्य बनाएं
  • इसे आमंत्रित करने के साथ आमंत्रित करें

यहां कुछ नमूना कोड है। ध्यान दें कि मैंने क्वेरी अभिव्यक्ति को डॉट नोटेशन में बदल दिया है - जब आप मूल रूप से केवल एक क्लॉज प्राप्त करते हैं तो क्वेरी अभिव्यक्ति का उपयोग करने में कोई बात नहीं है।

using System;
using System.Linq;
using System.Reflection;

namespace Interfaces
{
    interface IFoo {}
    interface IBar {}
    interface IBaz {}
}

public class Test
{
    public static void CallMe<T>()
    {
        Console.WriteLine("typeof(T): {0}", typeof(T));
    }

    static void Main()
    {
        MethodInfo method = typeof(Test).GetMethod("CallMe");

        var types = typeof(Test).Assembly.GetTypes()
                                .Where(t => t.Namespace == "Interfaces");

        foreach (Type type in types)
        {
            MethodInfo genericMethod = method.MakeGenericMethod(type);
            genericMethod.Invoke(null, null); // No target, no arguments
        }
    }
}

मूल उत्तर

आइए प्रारंभ करने के लिए एक चर "इंटरफ़ेस" को कॉल करने की स्पष्ट समस्याओं को छोड़ दें।

आपको इसे प्रतिबिंब से कॉल करना होगा। जेनेरिक का बिंदु संकलन समय पर अधिक प्रकार की जांच करना है। आप नहीं जानते कि किस प्रकार संकलन-समय पर है - इसलिए आपको जेनेरिक का उपयोग करना होगा।

जेनेरिक विधि प्राप्त करें, और उस पर MakeGenericMethod को कॉल करें, फिर उसे आमंत्रित करें।

क्या आपका इंटरफ़ेस स्वयं वास्तव में सामान्य है? मैं पूछता हूं क्योंकि आप मेकजेनेरिक टाइप पर कॉल कर रहे हैं, लेकिन किसी भी प्रकार के तर्क में गुजर नहीं रहे ... क्या आप कॉल करने की कोशिश कर रहे हैं

Method<MyNamespace.Interface<string>>(); // (Or whatever instead of string)

या

Method<MyNamespace.Interface>();

यदि यह उत्तरार्द्ध है, तो आपको केवल MakeGenericMethod पर कॉल की आवश्यकता है - MakeGenericType नहीं।

संपादित करें:

बेशक मेरा असली कोड बिल्कुल इस तरह दिखता नहीं है। मैंने अर्ध-छद्म कोड लिखने की कोशिश की ताकि मैं इसे और अधिक स्पष्ट कर सकूं।

ऐसा लगता है कि यह बदले में चीजों को गड़बड़ कर देता है।

तो, मैं वास्तव में क्या करना चाहता हूं यह है:

Method<Interface1>();
Method<Interface2>();
Method<Interface3>();
...

खैर ... मैंने सोचा कि शायद मैं प्रतिबिंब का उपयोग कर इसे लूप में बदल सकता हूं। तो सवाल यह है कि मैं इसे कैसे कर सकता हूं। मुझे प्रतिबिंब का बहुत उथला ज्ञान है। तो कोड उदाहरण बहुत अच्छा होगा।

परिदृश्य इस तरह दिखता है:

public void Method<T>() where T : class
{}
public void AnotherMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();

    var interfaces = from i in assembly.GetTypes()
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here
    select i;

    foreach(var i in interfaces)
    {
        Method<i>(); // Get compile error here!
    }



मूल पोस्ट:

नमस्ते!

मैं नामस्थान में सभी इंटरफेस के माध्यम से लूप करने की कोशिश कर रहा हूं और उन्हें इस तरह की सामान्य विधि के लिए तर्क के रूप में भेजता हूं:

public void Method<T>() where T : class
{}
public void AnotherMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();

    var interfaces = from i in assembly.GetTypes()
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here
    select i;

    foreach(var interface in interfaces)
    {
        Method<interface>(); // Get compile error here!
    }
}

मुझे जो त्रुटि मिलती है वह है "टाइप नाम अपेक्षित है, लेकिन स्थानीय चर नाम मिला"। अगर मैं कोशिश करता हूँ

...
    foreach(var interface in interfaces)
    {
        Method<interface.MakeGenericType()>(); // Still get compile error here!
    }
}

मुझे "ऑपरेटर लागू नहीं कर सकता '<' प्रकार 'ऑपरेटिंग समूह' और 'System.Type' के संचालन के लिए" इस समस्या को हल करने के बारे में कोई विचार?


एड्रियन गैलेरो के जवाब में जोड़ना:

टाइप जानकारी से जेनेरिक विधि को कॉल करने में तीन कदम शामिल हैं।

टीएलडीआर: किसी ऑब्जेक्ट के साथ एक ज्ञात जेनेरिक विधि को कॉल करके पूरा किया जा सकता है:

((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition()
    .MakeGenericMethod(typeof(string))
    .Invoke(this, null);

जहां GenericMethod<object> कॉल करने का विधि नाम है और किसी भी प्रकार जो सामान्य बाधाओं को पूरा करता है।

(एक्शन) यानी ( Func<string,string,int> या Action<bool> ) नामक विधि के हस्ताक्षर से मेल खाता है

चरण 1 जेनेरिक विधि परिभाषा के लिए MethodInfo प्राप्त कर रहा है

विधि 1: उपयुक्त प्रकार या बाध्यकारी झंडे के साथ GetMethod () या GetMethods () का उपयोग करें।

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");

विधि 2: प्रतिनिधि बनाएं, MethodInfo ऑब्जेक्ट प्राप्त करें और फिर GetGenericMethodDefinition को कॉल करें

कक्षाओं के अंदर से विधियों में शामिल हैं:

MethodInfo method = ((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();

कक्षा के बाहर से जिसमें विधियां हैं:

MethodInfo method = ((Action)(new Sample())
    .GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)Sample.StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();

सी # में, एक विधि का नाम, यानी "ToString" या "GenericMethod" वास्तव में उन विधियों के समूह को संदर्भित करता है जिनमें एक या अधिक विधियां हो सकती हैं। जब तक आप विधि पैरामीटर के प्रकार प्रदान नहीं करते हैं, यह ज्ञात नहीं है कि आप किस विधि का जिक्र कर रहे हैं।

((Action)GenericMethod<object>) एक विशिष्ट विधि के लिए प्रतिनिधि को संदर्भित करता है। ((Func<string, int>)GenericMethod<object>) जेनेरिक मोड के एक अलग अधिभार को संदर्भित करता है

विधि 3: एक विधि कॉल अभिव्यक्ति युक्त लैम्ब्डा अभिव्यक्ति बनाएं, MethodInfo ऑब्जेक्ट प्राप्त करें और फिर GetGenericMethodDefinition

MethodInfo method = ((MethodCallExpression)((Expression<Action<Sample>>)(
    (Sample v) => v.GenericMethod<object>()
    )).Body).Method.GetGenericMethodDefinition();

यह नीचे टूट जाता है

एक लैम्ब्डा अभिव्यक्ति बनाएं जहां शरीर आपकी वांछित विधि पर कॉल करता है।

Expression<Action<Sample>> expr = (Sample v) => v.GenericMethod<object>();

शरीर निकालें और MethodCallExpression पर डालें

MethodCallExpression methodCallExpr = (MethodCallExpression)expr.Body;

विधि से जेनेरिक विधि परिभाषा प्राप्त करें

MethodInfo methodA = methodCallExpr.Method.GetGenericMethodDefinition();

चरण 2 उचित प्रकार (ओं) के साथ एक सामान्य विधि बनाने के लिए MakeGenericMethod को कॉल कर रहा है।

MethodInfo generic = method.MakeGenericMethod(myType);

चरण 3 उपयुक्त तर्कों के साथ विधि का आह्वान कर रहा है।

generic.Invoke(this, null);




c# linq generics reflection