एक सामान्य प्रकार के पैरामीटर पर एक स्थिर विधि को कॉल करना


107

मैं ऐसा कुछ करने की उम्मीद कर रहा था, लेकिन यह सी # में अवैध प्रतीत होता है:


public Collection MethodThatFetchesSomething<T>()
    where T : SomeBaseClass
{
    return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}

मुझे एक संकलन-समय त्रुटि मिलती है: "'T' एक 'टाइप पैरामीटर' है, जो दिए गए संदर्भ में मान्य नहीं है।"

एक सामान्य प्रकार के पैरामीटर को देखते हुए, मैं सामान्य वर्ग पर एक स्थिर विधि कैसे कह सकता हूं? स्थैतिक विधि को उपलब्ध होना चाहिए, बाधा को देखते हुए।


जवाबों:


58

इस मामले में आपको बस सीधे स्थिर प्रकार पर स्थिर विधि को कॉल करना चाहिए। C # (और CLR) वर्चुअल स्टैटिक विधियों का समर्थन नहीं करता है। इसलिए:

T.StaticMethodOnSomeBaseClassThatReturnsCollection

... से अलग नहीं हो सकता है:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

सामान्य प्रकार के पैरामीटर के माध्यम से जाना एक अप्रत्यक्ष अप्रत्यक्ष है और इसलिए समर्थित नहीं है।


25
लेकिन क्या होगा अगर आप एक बच्चे की कक्षा में अपनी स्थैतिक विधि का मुखौटा लगाते हैं? सार्वजनिक वर्ग SomeChildClass: SomeBaseClass {public new static StaticMethodOnSomeBaseClassThatReturnsCollection () {}} क्या आप उस स्थैतिक विधि को एक सामान्य प्रकार से एक्सेस करने के लिए कुछ कर सकते हैं?
ह्यूगो मिग्नरॉन

2
नीचे जोशुआ पीच के जवाब की जाँच करें, मुझे विश्वास है कि उस मामले में काम करेगा।
रेमी डेस्प्रेस-स्माइथ

1
चाहेंगे return SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection();काम करते हैं? यदि ऐसा है तो आप इसे अपने उत्तर में जोड़ना चाह सकते हैं। धन्यवाद। इसने मेरे लिए काम किया। मेरे मामले में मेरी कक्षा में एक प्रकार का परम था इसलिए मैंने किया return SomeBaseClass<T>.StaticMethodOnSomeBaseClassThatReturnsCollection();और वह काम किया।
टोड्डो

27

पिछले उत्तर के बारे में विस्तार से बताने के लिए, मुझे लगता है कि प्रतिबिंब यहाँ आपके करीब है। मैं 1001 कारण दे सकता हूं कि आपको कुछ करना चाहिए या नहीं करना चाहिए, मैं आपके प्रश्न का उत्तर केवल पूछूंगा। मुझे लगता है कि आपको गेटमेथोड विधि को जेनेरिक पैरामीटर के प्रकार पर कॉल करना चाहिए और वहां से जाना चाहिए। उदाहरण के लिए, एक समारोह के लिए:

public void doSomething<T>() where T : someParent
{
    List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
    //do something with items
}

जहाँ T कोई भी वर्ग है जिसमें स्थिर विधि fetchAll () है।

हां, मुझे पता है कि यह बहुत ही धीमी गति से है और दुर्घटना हो सकती है अगर someParent अपने सभी बच्चे वर्गों को लाने के लिए बाध्य नहीं करता है, लेकिन यह पूछे गए प्रश्न का उत्तर देता है।


2
नहीं, कदापि नहीं। JaredPar को यह बिल्कुल सही लगा: T.StaticMethodOnSomeBaseClassThatReturnsCollection जहां T: SomeBaseClass, SomeBaseClass.StaticBethodOnSomeBaseTaseRassTurnReturnsCollection बताते हुए अलग नहीं है।
रेमी डेस्प्रेस-स्माइथ

2
यह वही है जो मुझे चाहिए था, यह एक स्थिर विधि के साथ काम करता है
myro

यह वह उत्तर था जिसकी मुझे आवश्यकता थी क्योंकि मेरे पास कक्षाओं और आधार वर्ग का नियंत्रण नहीं था।
टिम

8

इस तरह की पद्धति को कॉल करने का एकमात्र तरीका प्रतिबिंब के माध्यम से होगा, हालांकि, ऐसा लगता है कि इंटरफ़ेस में उस कार्यक्षमता को लपेटना और उदाहरण-आधारित IoC / factory / etc पैटर्न का उपयोग करना संभव हो सकता है।


5

ऐसा लगता है कि आप इस तथ्य के इर्द-गिर्द काम करने के लिए जेनरिक का उपयोग करने की कोशिश कर रहे हैं कि C # में "वर्चुअल स्टैटिक तरीके" नहीं हैं।

दुर्भाग्य से, यह काम नहीं कर रहा है।


1
मैं नहीं हूँ - मैं एक उत्पन्न DAL परत के ऊपर काम कर रहा हूँ। उत्पन्न कक्षाएं सभी एक बेस क्लास से विरासत में मिली हैं, जिसमें एक स्थिर FetchAll विधि है। मैं एक "जेनेरिक" रिपॉजिटरी वर्ग के साथ अपने रिपॉजिटरी वर्ग में कोड दोहराव को कम करने की कोशिश कर रहा हूं - उपयोग किए गए कंक्रीट वर्ग को छोड़कर, बहुत से दोहराए गए कोड।
रेमी डेस्प्रेस-स्माइथ

1
तो फिर आप SomeBaseClass.StaticMethod ... () को कॉल क्यों नहीं करते?
ब्रैड विल्सन

क्षमा करें, मैंने पिछली टिप्पणी में खुद को अच्छी तरह से नहीं समझाया। FetchAll को आधार पर परिभाषित किया गया है, लेकिन व्युत्पन्न वर्गों पर लागू किया गया है। मुझे इसे व्युत्पन्न वर्ग पर बुलाना होगा।
रेमी डेस्प्रेस-स्माइथ

7
यदि यह एक स्थिर विधि है, तो यह आधार द्वारा परिभाषित और कार्यान्वित दोनों है। C # में वर्चुअल / एब्स्ट्रैक्ट स्टैटिक मेथड जैसी कोई चीज नहीं है, और ऐसे के लिए कोई ओवरराइड नहीं है। मुझे संदेह है कि आपने इसे फिर से घोषित किया है, जो बहुत अलग है।
मार्क Gravell

1
हां, आप सही हैं - मैंने यहां अवैध धारणाएं बनाई थीं। चर्चा के लिए धन्यवाद, इसने मुझे सही रास्ते पर लाने में मदद की।
रेमी Despres-Smyth

2

अब तक, आप नहीं कर सकते। आपको कंपाइलर को यह बताने का एक तरीका चाहिए कि T में वह विधि है, और वर्तमान में, ऐसा करने का कोई तरीका नहीं है। (कई जेनेरिक अवरोध में निर्दिष्ट किए जा सकने के लिए Microsoft को आगे बढ़ा रहे हैं, इसलिए भविष्य में यह संभव होगा)।


1
समस्या यह है कि क्योंकि जेनेरिक रनटाइम द्वारा प्रदान किए जाते हैं, इसका मतलब शायद एक नया सीएलआर संस्करण होगा - जिसे उन्होंने (बड़े पैमाने पर) 2.0 के बाद से बचा लिया है। हो सकता है कि हम, एक नया एक कारण हो हालांकि ...
मार्क Gravell

2

यहां, मैं एक उदाहरण पोस्ट करता हूं जो काम करता है, यह एक वर्कअराउंड है

public interface eInterface {
    void MethodOnSomeBaseClassThatReturnsCollection();
}

public T:SomeBaseClass, eInterface {

   public void MethodOnSomeBaseClassThatReturnsCollection() 
   { StaticMethodOnSomeBaseClassThatReturnsCollection() }

}

public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{ 
   return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}

2
यह मेरे लिए एक सिंटैक्स त्रुटि देता है? क्या public T : SomeBaseClassमतलब है?
एरिक

यदि आपकी कक्षा के पास कुछ इंस्टेंस मेथोड है () तो आप कॉल कर सकते हैं (नया T) (।)। कुछ InManceMethod (); - लेकिन यह एक उदाहरण विधि कह रहा है - सवाल पूछा गया कि कक्षा की एक स्थैतिक विधि को कैसे कॉल किया जाए।
टिमोथी

2

मैं सिर्फ इसे बाहर फेंकना चाहता था कि कभी-कभी प्रतिनिधि इन समस्याओं को हल करते हैं, संदर्भ के आधार पर।

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

उदाहरण के लिए:

class Factory<TProduct> where TProduct : new()
{
    public delegate void ProductInitializationMethod(TProduct newProduct);


    private ProductInitializationMethod m_ProductInitializationMethod;


    public Factory(ProductInitializationMethod p_ProductInitializationMethod)
    {
        m_ProductInitializationMethod = p_ProductInitializationMethod;
    }

    public TProduct CreateProduct()
    {
        var prod = new TProduct();
        m_ProductInitializationMethod(prod);
        return prod;
    }
}

class ProductA
{
    public static void InitializeProduct(ProductA newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class ProductB
{
    public static void InitializeProduct(ProductB newProduct)
    {
        // .. Do something with a new ProductA
    }
}

class GenericAndDelegateTest
{
    public static void Main()
    {
        var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
        var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);

        ProductA prodA = factoryA.CreateProduct();
        ProductB prodB = factoryB.CreateProduct();
    }
}

दुर्भाग्य से आप यह लागू नहीं कर सकते हैं कि कक्षा में सही विधि है, लेकिन आप कम से कम संकलन-समय लागू कर सकते हैं कि परिणामी फ़ैक्टरी विधि में वह सब कुछ है जिसकी वह अपेक्षा करता है (यानी बिल्कुल सही हस्ताक्षर के साथ एक आरंभीकरण विधि)। यह रन टाइम रिफ्लेक्शन अपवाद से बेहतर है।

इस दृष्टिकोण के कुछ लाभ भी हैं, यानी आप init के तरीकों का पुन: उपयोग कर सकते हैं, उदाहरण के तरीके, आदि हो सकते हैं।


1

आपको प्रतिबिंब का उपयोग करने में सक्षम होना चाहिए, जैसा कि यहां वर्णित है

लिंक मृत होने के कारण, मुझे संबंधित विवरण मशीन में मिला:

मान लें कि आपके पास एक स्टैटिक जेनेरिक विधि है:

class ClassWithGenericStaticMethod
{
    public static void PrintName<T>(string prefix) where T : class
    {
        Console.WriteLine(prefix + " " + typeof(T).FullName);
    }
}

आप इस पद्धति का उपयोग कैसे कर सकते हैं?

यह बहुत आसान हो जाता है ... यह है कि आप चिंतन का उपयोग कर एक स्टेटिक जेनेरिक विधि कैसे लागू करते हैं:

// Grabbing the type that has the static generic method
Type typeofClassWithGenericStaticMethod = typeof(ClassWithGenericStaticMethod);

// Grabbing the specific static method
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethod("PrintName", System.Reflection.BindingFlags.Static | BindingFlags.Public);

// Binding the method info to generic arguments
Type[] genericArguments = new Type[] { typeof(Program) };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

// Simply invoking the method and passing parameters
// The null parameter is the object to call the method from. Since the method is
// static, pass null.
object returnValue = genericMethodInfo.Invoke(null, new object[] { "hello" });

लिंक मर चुका है।
नेक्रोनोमिकॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.