जेनरिक में टी आउट बनाम वी <टी>


188

बीच क्या अंतर है <out T>और <T>? उदाहरण के लिए:

public interface IExample<out T>
{
    ...
}

बनाम

public interface IExample<T>
{
    ...
}

1
Mscorlib में सिस्टम ns में परिभाषित अच्छा उदाहरण IObservable <T> और IObserver <T> होगा। सार्वजनिक इंटरफ़ेस IObservable <T>, और सार्वजनिक इंटरफ़ेस IObserver <T> में। इसी तरह, IEnumerator <out T>, IEnumerable <out T>
VivekDev

1
सबसे अच्छी व्याख्या जो मुझे मिली: agirlamonggeeks.com/2019/05/29/… । (< In T> <- का अर्थ है कि T को केवल एक विधि के पैरामीटर के रूप में पारित किया जा सकता है; <out T> <- का अर्थ है कि T हो सकता है; केवल विधि के परिणाम के रूप में लौटे)
उलदज़िर शायरी

जवाबों:


211

outजेनरिक में कीवर्ड निरूपित करने के लिए है कि इंटरफ़ेस में प्रकार टी covariant है प्रयोग किया जाता है। देखें सहप्रसरण और contravariance जानकारी के लिए।

क्लासिक उदाहरण है IEnumerable<out T>। चूंकि IEnumerable<out T>सहसंयोजक है, तो आपको निम्न कार्य करने की अनुमति है:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

ऊपर से दूसरी पंक्ति विफल हो जाती है अगर यह सहसंयोजक नहीं था, भले ही तार्किक रूप से यह काम करना चाहिए, क्योंकि स्ट्रिंग ऑब्जेक्ट से प्राप्त होती है। जेनेरिक इंटरफेस में विचरण से पहले C # और VB.NET (वीएस 2010 के साथ .NET 4 में) जोड़ा गया था, यह एक अनिवार्य समय त्रुटि थी।

.NET 4 के बाद IEnumerable<T>, सहसंयोजक के रूप में चिह्नित किया गया था, और बन गया IEnumerable<out T>। चूंकि IEnumerable<out T>केवल इसके भीतर के तत्वों का उपयोग किया जाता है, और उन्हें कभी नहीं जोड़ता / बदलता है, इसलिए यह इसके लिए सुरक्षित है कि यह वस्तुओं के एक संग्रहणीय संग्रह के रूप में तार के एक अनगिनत संग्रह का इलाज करे, जिसका अर्थ है कि यह सहसंयोजक है

यह एक प्रकार के साथ काम नहीं करेगा IList<T>, क्योंकि IList<T>एक Addविधि है। मान लीजिए कि यह अनुमति दी जाएगी:

IList<string> strings = new List<string>();
IList<object> objects = strings;  // NOTE: Fails at compile time

आप तब कॉल कर सकते हैं:

objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object

यह, निश्चित रूप से, असफल होगा - इसलिए IList<T>सहसंयोजक चिह्नित नहीं किया जा सकता है।

इसके अलावा, btw, के लिए एक विकल्प है in- जो तुलना इंटरफेस जैसी चीजों द्वारा उपयोग किया जाता है। IComparer<in T>, उदाहरण के लिए, विपरीत तरीके से काम करता है। आप एक ठोस उपयोग कर सकते हैं IComparer<Foo>एक के रूप में सीधे IComparer<Bar>यदि Barका एक उपवर्ग है Foo, क्योंकि IComparer<in T>इंटरफेस है contravariant


4
@ColeJohnson क्योंकि Imageएक सार वर्ग है;) आप new List<object>() { Image.FromFile("test.jpg") };बिना किसी समस्या के कर सकते हैं, या आप भी कर सकते हैं new List<object>() { new Bitmap("test.jpg") };। आप के साथ समस्या यह है कि new Image()अनुमति नहीं है (आप भी नहीं कर सकते var img = new Image();हैं)
रीड कोपसे

4
जेनेरिक IList<object>एक विचित्र उदाहरण है, यदि आप चाहते हैं कि objectआपको जेनेरिक की आवश्यकता न हो।
जोडरेल

5
@ReedCopsey क्या आप अपनी टिप्पणी में अपने खुद के जवाब का विरोध नहीं कर रहे हैं?
10

64

आसानी से inऔर outकीवर्ड के उपयोग को याद रखने के लिए (कोविरियन और कंट्रोवर्सी), हम इनहेरिटेंस को रैपर्स के रूप में चित्रित कर सकते हैं:

String : Object
Bar : Foo

अंदर बाहर


11
क्या यह गलत तरीका नहीं है? विपरीतता = में = कम व्युत्पन्न प्रकारों को अधिक व्युत्पन्न के स्थान पर उपयोग करने की अनुमति देता है। / Covariance = out = कम व्युत्पन्न के स्थान पर अधिक व्युत्पन्न प्रकारों का उपयोग करने की अनुमति देता है। व्यक्तिगत रूप से, आपके चित्र को देखकर, मैंने इसे उस के विपरीत के रूप में पढ़ा।
सैम शील्स

सह यू संस्करण (: मेरे लिए
एसआर

49

विचार करें,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

और कार्य,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

फ़ंक्शन जो स्वीकार करता है वह स्वीकार ICovariantSkinned<Fruit>करने में सक्षम होगा ICovariantSkinned<Fruit>या ICovariantSkinned<Bananna>क्योंकि ICovariantSkinned<T>एक सहसंयोजक इंटरफ़ेस है और Bananaएक प्रकार का है Fruit,

फ़ंक्शन जो स्वीकार करता है ISkinned<Fruit>वह केवल स्वीकार करने में सक्षम होगा ISkinned<Fruit>


37

" out T" का अर्थ है कि प्रकार T"सहसंयोजक" है। यह Tकेवल सामान्य वर्ग, इंटरफ़ेस या विधि के तरीकों में एक लौटे (आउटबाउंड) मान के रूप में प्रदर्शित होने के लिए प्रतिबंधित करता है। निहितार्थ यह है कि आप सुपर के प्रकार के साथ टाइप / इंटरफ़ेस / विधि को एक बराबर कर सकते हैं T
जैसे ICovariant<out Dog>को कास्ट किया जा सकता है ICovariant<Animal>


13
मुझे यह महसूस नहीं हुआ कि यह outलागू किया Tजा सकता है, जब तक कि मैं इस उत्तर को नहीं पढ़ता। पूरी अवधारणा अब अधिक समझ में आता है!
मारियोडीएस

6

आपके द्वारा पोस्ट की गई लिंक से…।

सामान्य प्रकार के मापदंडों के लिए, आउट कीवर्ड निर्दिष्ट करता है कि प्रकार पैरामीटर सहसंयोजक है

संपादित करें : फिर से, आपके द्वारा पोस्ट किए गए लिंक से

अधिक जानकारी के लिए, Covariance and Contravariance (C # और Visual Basic) देखें। http://msdn.microsoft.com/en-us/library/ee207183.aspx

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