2011-11-11 2 views
8

मैं एक टी 4 टेम्पलेट पर एक विशेष कार्य में इसका उपयोग करने के लिए एक सामान्यीकृत विधि लिख रहा हूं। विधि मुझे सामान्य इंटरफ़ेस से विशेष प्रकारों का उपयोग करने की अनुमति देनी चाहिए। मैं निम्नलिखित हस्ताक्षर के बारे में सोचा:एक सामान्य विधि contravariant/covariant प्रकारों का उपयोग कर सकते हैं?

interface IGreatInterface { 
    Object aMethodAlpha<U>(U parameter) where U : IAnInterface; 
    Object aMethodBeta(IAnInterface parameter) 
} 

public class AnInterestingClass : IAnInterface{} 

जब मैं क्योंकि मुझे लगता है कि विधि यानी IAnInterface की एक उप-प्रकार (मुझे लगता है कि लागू करना चाहते हैं का उपयोग कर लिखने के लिए मेरी टी -4 कर दिया है IGreatInterface संकलक झंडे aMethodBeta() के लिए एक त्रुटि को लागू करने की कोशिश इस तरह की विधि: Object aMethodBeta(AnInterestingClass parameter))।

विधि aMethodAlpha<U>() का उपयोग किया जा सकता है लेकिन जैसा कि मैं चाहता हूं उतना स्वच्छ नहीं है क्योंकि मेरे टी 4 को कुछ अतिरिक्त कोड उत्पन्न करना है। मैं (शायद गलत) प्रस्तावित करता है कि उस विधि का कार्यान्वयन, जिसे टी 4 द्वारा किया जाना है,
Object aMethodAlpha<AnInterestingClass>(AnInterestingClass parameter) हो सकता है।

मुझे लगता है कि जेनेरिक तरीके contravariant प्रकारों का समर्थन नहीं करते हैं, लेकिन मुझे यकीन नहीं है; मुझे लगता है कि यह रास्ता संकलक सांकेतिक शब्दों में बदलनेवाला सामान्य प्रकार में परिभाषित नहीं एक विधि होने एक विशेष प्रकार का उपयोग करने के लिए रोकता है ...

  1. एक सामान्य विधि जब लागू की जा रही सही प्रकार का उपयोग है?
  2. क्या इस व्यवहार को बदलने के लिए कोई चाल है?
+0

मुझे आपके प्रश्न को काफी समझ में नहीं आता है। क्या आप कोड पोस्ट कर सकते हैं जो IGreatInterface और विशिष्ट कंपाइलर त्रुटि लागू करता है? – phoog

+2

@ जुआन: बस एक साइड नोट के रूप में यह आपके अपडेट को * अपडेट * या कुछ के साथ चिह्नित करने में मदद करता है ताकि हम देख सकें कि क्या बदला गया है। –

उत्तर

20

यह सवाल काफी भ्रमित है । मुझे देखने दो कि क्या मैं इसे स्पष्ट कर सकता हूं।

जब मैं क्योंकि मुझे लगता है कि विधि एक उपप्रकार IAnInterface की मैं इस तरह कि विधि लागू करना चाहते हैं का उपयोग कर बनाया है aMethodBeta() के लिए IGreatInterface संकलक झंडे एक त्रुटि को लागू करने का प्रयास करें: Object aMethodBeta(AnInterestingClass parameter)

यह कानूनी नहीं है। कुछ हद तक सरल बनाना:

class Food {} 
class Fruit : Food {} 
class Meat : Food {} 
interface IEater 
{ 
    void Eat(Food food); 
} 
class Vegetarian : IEater 
{ 
    public void Eat(Fruit fruit); 
} 

कक्षा VegetarianIEater के अनुबंध को पूरा नहीं करता है। आपको किसी भी खाने के लिए भोजन करने में सक्षम होना चाहिए, लेकिन Vegetarian केवल फल स्वीकार करता है। सी # वर्चुअल विधि औपचारिक पैरामीटर covariance का समर्थन नहीं करता है क्योंकि यह टाइपएफ़ नहीं है।

अब, आप तो कहते हैं, कैसे इस बारे में:

interface IFruitEater 
{ 
    void Eat(Fruit fruit); 
} 
class Omnivore : IFruitEater 
{ 
    public void Eat(Food food); 
} 

अब हम प्रकार सुरक्षा मिल गया है; Omnivore को IFruitEater के रूप में उपयोग किया जा सकता है क्योंकि Omnivore फल, साथ ही साथ कोई अन्य भोजन भी खा सकता है।

दुर्भाग्य से, सी # आभासी विधि औपचारिक पैरामीटर प्रकार contravariance भले ही ऐसा करने से सिद्धांत typesafe में है का समर्थन नहीं करता। कुछ भाषाएं इसका समर्थन करती हैं।

इसी प्रकार, सी # वर्चुअल विधि रिटर्न प्रकार भिन्नता का समर्थन नहीं करता है।

मुझे यकीन नहीं है कि वास्तव में आपके प्रश्न का उत्तर दिया गया है या नहीं। क्या आप इस सवाल को स्पष्ट कर सकते हैं?

अद्यतन:

के बारे में क्या:

interface IEater 
{ 
    void Eat<T>(T t) where T : Food; 
} 
class Vegetarian : IEater 
{ 
    // I only want to eat fruit! 
    public void Eat<Fruit>(Fruit food) { } 
} 

नहीं, कि नहीं कानूनी या तो है। IEater का अनुबंध यह है कि आप एक विधि Eat<T> प्रदान करेंगे जो T ले सकता है जो Food है।आप नहीं आंशिक रूप से अनुबंध, किसी भी अधिक की तुलना में आप ऐसा कर सकता है लागू कर सकते हैं:

interface IAdder 
{ 
    int Add(int x, int y); 
} 
class Adder : IAdder 
{ 
    // I only know how to add two! 
    public int Add(2, int y){ ... } 
} 

लेकिन, आप यह कर सकते हैं:

interface IEater<T> where T : Food 
{ 
    void Eat(T t); 
} 
class Vegetarian : IEater<Fruit> 
{ 
    public void Eat(Fruit fruit) { } 
} 

कि पूरी तरह से कानूनी है। हालांकि, अगर आप ऐसा नहीं कर सकते:

interface IEater<T> where T : Food 
{ 
    void Eat(T t); 
} 
class Omnivore : IEater<Fruit> 
{ 
    public void Eat(Food food) { } 
} 

क्योंकि फिर, सी # आभासी विधि औपचारिक पैरामीटर contravariance या सहप्रसरण का समर्थन नहीं करता।

ध्यान दें कि सी # समर्थन पैरामीट्रिक पोलिमोर्फ़िज्मके सहप्रसरण जब ऐसा करने से typesafe माना जाता है करता है। उदाहरण के लिए, यह कानूनी है:

IEnumerable<Fruit> fruit = whatever; 
IEnumerable<Food> food = fruit; 

फल का एक अनुक्रम भोजन के एक दृश्य के रूप में इस्तेमाल किया जा सकता है। या,

IEnumerable<Fruit> fruitComparer = whatever; 
IComparable<Apples> appleComparer = fruitComparer; 

यदि आपके पास ऐसा कुछ है जो किसी भी दो फलों की तुलना कर सकता है तो यह किसी भी दो सेब की तुलना कर सकता है।

हालांकि, इस प्रकार का कॉन्वर्सिस और contravariance केवल कानूनी है जब निम्नलिखित सभी सत्य हैं: (1) भिन्नता प्रकार टाइपफेफ है, (2) प्रकार के लेखक जोड़ा वांछित एनोटेशन वांछित सह- और अनुबंध का संकेत -वृत्त, (3) शामिल विभिन्न प्रकार के तर्क सभी संदर्भ प्रकार हैं, (4) जेनेरिक प्रकार या तो एक प्रतिनिधि या इंटरफ़ेस है।

+0

(महान उत्तर! इस टिप्पणी का उपयोग बाद में प्रश्न को स्पष्ट करने के लिए किया जाएगा ...)। अपने उदाहरण का उपयोग करना: क्या मैं एक हस्ताक्षर 'आईटर' बना सकता हूं। (टी भोजन) जहां टी: खाद्य' और फिर 'Omnivore.Eat (फल भोजन) लागू करें? 'आईटर' को लागू नहीं करने के लिए मुझे कंप्रेसर के बिना फ़्लैग किए। (टी भोजन) खाओ '? आपके उत्तर से मुझे लगता है कि यह संभव नहीं है ... – JPCF

+0

@JuanPabloContreras: मैंने आपकी टिप्पणी के बारे में कुछ अतिरिक्त पाठ जोड़ा है। –

+0

@EricLippert यदि संभव हो तो कृपया इस प्रश्न पर अपने विचार दें http://stackoverflow.com/questions/8109478/process-address-space-vs-virtual-memory – Sandeep

2

यदि आप एक सामान्य इंटरफ़ेस से प्राप्त करना चाहते हैं, तो फ़ूग का जवाब देखें। यदि आप एक इंटरफ़ेस को सह-रूप से कार्यान्वित करने की कोशिश करने के बारे में बात कर रहे हैं, जो नीचे मेरी चर्चा की ओर जाता है।

मान लें:

internal interface IAnInterface { } 

public class SomeSubClass : IAnInterface { } 

public class AnotherSubClass : IAnInterface { } 

public GreatClass : IGreatInterface { ... } 

एक और अधिक व्युत्पन्न (सह संस्करण) के साथ इंटरफ़ेस को लागू करने तर्क वहाँ कोई गारंटी जब यह एक अंतरफलक है कि एक IAnInterface में पारित एक हो जाएगा के माध्यम से कहा जाता है है की कोशिश कर के साथ समस्या SomeSubClass उदाहरण। यही कारण है कि यह सीधे अनुमति नहीं है।

IGreatInterface x = new GreatClass(); 

x.aMethodBeta(new AnotherSubClass()); 

यदि आप सहप्रसरण कर सकता है, यह विफल हो जाएगा क्योंकि आप एक SomeSubClass उम्मीद की जाएगी, लेकिन एक AnotherSubClass मिलेगा।

क्या आप सकता है कर स्पष्ट इंटरफेस कार्यान्वयन करना है:

class GreatInterface : IGreatInterface 
{ 
    // explicitly implement aMethodBeta() when called from interface reference 
    object IGreatInterface.aMethodBeta(IAnInterface parameter) 
    { 
     // do whatever you'd do on IAnInterface itself... 
     var newParam = parameter as SomeSubClass; 

     if (newParam != null) 
     { 
      aMethodBeta(newParam); 
     } 

     // otherwise do some other action... 
    } 

    // This version is visible from the class reference itself and has the 
    // sub-class parameter 
    public object aMethodBeta(SomeSubClass parameter) 
    { 
     // do whatever 
    } 
} 

इस प्रकार, यदि आप ऐसा किया, अपने इंटरफेस सामान्य, का समर्थन करता है वर्ग एक अधिक विशिष्ट विधि है, लेकिन अभी भी इंटरफ़ेस का समर्थन करता है । मुख्य अंतर यह अद्यतन आप इस मामले में जहां IAnInterface की एक अप्रत्याशित कार्यान्वयन में पारित हो जाता है संभाल करने के लिए आवश्यकता होगी है

:। यह लगता है कि आप कुछ इस तरह हैं:

public interface ISomeInterface 
{ 
    void SomeMethod<A>(A someArgument); 
} 

public class SomeClass : ISomeInterface 
{ 
    public void SomeMethod<TA>(TA someArgument) where TA : SomeClass 
    { 

    } 
} 

यह अनुमति नहीं है , जब आप किसी इंटरफ़ेस से सामान्य विधि लागू करते हैं, तो बाधाओं का मिलान होना चाहिए।

+0

hmmm ... आपके उत्तर से मैं अनुमान लगा सकता हूं कि नेट सामान्य तरीकों के साथ उपप्रकार स्वीकार नहीं करता है ... क्या मैं सही हूँ? – JPCF

+0

@ जुआन: मुझे यकीन नहीं है कि आपका क्या मतलब है "स्वीकार नहीं करता"। क्या आप तर्क के रूप में मतलब है? पैरामीटर प्रकार के रूप में? –

+0

@ जुआन: यदि आपका मतलब है कि मैं एक इंटरफ़ेस को कार्यान्वित कर सकता हूं लेकिन इंटरफ़ेस प्रकार से अधिक प्रकार का व्युत्पन्न कर सकता हूं? नहीं, आप नहीं कर सकते। आप सह-भिन्नता से, विरोधाभासी रूप से पास/वापसी तर्क कर सकते हैं, और आप सह-भिन्नता से, अंतर-भिन्न रूप से इंटरफेस और प्रतिनिधियों को असाइन कर सकते हैं (अगर उचित रूप से चिह्नित किया गया हो), लेकिन कार्यान्वयन नहीं। –

0

हो सकता है कि आप इस के लिए देख रहे:

interface IGreatInterface<in U> where U : IAnInterface 
{ 
    Object aMethodAlpha(U parameter); 
} 

class SomeClass : IAnInterface { /*...*/ } 

class GreatClass : IGreatInterface<SomeClass> 
{ 
    public Object aMethodAlpha(SomeClass parameter) {} 
} 

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

हाँ, तुम ठीक कह रहे: यदि आप एक इंटरफेस में एक सामान्य विधि को परिभाषित, तो आप एक साथ कि विधि लागू नहीं कर सकते एक संगत प्रकार का उपयोग कर ठोस विधि।

कैसे एक प्रतिनिधि का उपयोग कर के बारे में (के बाद से प्रतिनिधियों का समर्थन सह और contravariance):

[उदाहरण नष्ट कर दिया क्योंकि मैं विचरण पीछे की ओर मिला - यह काम नहीं करता।]

+0

नहीं ... कृपया अद्यतन पढ़ें ... – JPCF

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