इसके साथ <out T>
, आप इंटरफ़ेस संदर्भ को पदानुक्रम में एक ऊपर की तरफ मान सकते हैं।
इसके साथ <in T>
, आप hi hi में इंटरफ़ेस संदर्भ को एक नीचे की ओर मान सकते हैं।
मुझे इसे और अधिक अंग्रेजी शब्दों में समझाने की कोशिश करते हैं।
मान लीजिए कि आप अपने चिड़ियाघर से जानवरों की एक सूची प्राप्त कर रहे हैं, और आप उन्हें संसाधित करने का इरादा रखते हैं। सभी जानवरों (आपके चिड़ियाघर में) का एक नाम, और एक अद्वितीय आईडी है। कुछ जानवर स्तनधारी हैं, कुछ सरीसृप हैं, कुछ उभयचर हैं, कुछ मछली आदि हैं, लेकिन वे सभी जानवर हैं।
इसलिए, आपकी जानवरों की सूची (जिसमें विभिन्न प्रकार के जानवर शामिल हैं) के साथ, आप कह सकते हैं कि सभी जानवरों का एक नाम है, इसलिए जाहिर है कि सभी जानवरों का नाम प्राप्त करना सुरक्षित होगा।
हालांकि, क्या होगा यदि आपके पास केवल मछलियों की सूची है, लेकिन उन्हें जानवरों की तरह व्यवहार करने की आवश्यकता है, क्या वह काम करता है? सहज रूप से, यह काम करना चाहिए, लेकिन C # 3.0 और इससे पहले, कोड का यह टुकड़ा संकलित नहीं करेगा:
IEnumerable<Animal> animals = GetFishes();
इसका कारण यह है कि संकलक को यह नहीं पता "कि आप क्या चाहते हैं, या आप इसे पुनः प्राप्त करने के बाद जानवरों के संग्रह के साथ कर सकते हैं" । यह सब जानता है, IEnumerable<T>
एक वस्तु को सूची में वापस लाने के माध्यम से एक रास्ता हो सकता है , और यह संभवतः आपको एक ऐसा जानवर डालने की अनुमति देगा जो मछली नहीं है, केवल मछली को शामिल करने वाले संग्रह में।
दूसरे शब्दों में, संकलक गारंटी नहीं दे सकता है कि यह अनुमति नहीं है:
animals.Add(new Mammal("Zebra"));
तो कंपाइलर सिर्फ आपके कोड को संकलित करने से इनकार करता है। यह सहसंयोजक है।
आइए कंट्रोवर्सी को देखें।
चूंकि हमारा चिड़ियाघर सभी जानवरों को संभाल सकता है, यह निश्चित रूप से मछली को संभाल सकता है, तो आइए हमारे चिड़ियाघर में कुछ मछलियों को जोड़ने की कोशिश करें।
C # 3.0 और इससे पहले, यह संकलित नहीं करता है:
List<Fish> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));
यहाँ, कंपाइलर इस कोड को अनुमति दे सकता है , भले ही यह विधि List<Animal>
केवल इसलिए लौटे क्योंकि सभी मछलियाँ पशु हैं, इसलिए यदि हमने इसके प्रकार बदल दिए हैं:
List<Animal> fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));
तब यह काम करेगा, लेकिन संकलक यह निर्धारित नहीं कर सकता है कि आप ऐसा करने की कोशिश नहीं कर रहे हैं:
List<Fish> fishes = GetAccessToFishes();
Fish firstFist = fishes[0];
चूंकि सूची वास्तव में जानवरों की सूची है, इसलिए इसे अनुमति नहीं है।
इसलिए, गर्भनिरोधक और सह-विचरण कैसे आप वस्तु संदर्भों का इलाज करते हैं और आपको उनके साथ क्या करने की अनुमति है।
in
और out
सी में कीवर्ड # 4.0 विशेष रूप से के निशान एक या अन्य रूप में इंटरफ़ेस। के साथ in
, आपको जेनेरिक प्रकार (आमतौर पर टी) को इनपुट- एक्सपोजिशन में रखने की अनुमति दी जाती है , जिसका अर्थ है विधि तर्क और लेखन-केवल गुण।
इसके साथ out
, आपको सामान्य प्रकार को आउटपुट- एक्सपोज़िशन में रखने की अनुमति है , जो कि विधि रिटर्न मान, रीड-ओनली प्रॉपर्टीज़, और मेथड पैरामीटर पैरामीटर है।
यह आपको वह करने की अनुमति देगा जो कोड के साथ करना है:
IEnumerable<Animal> animals = GetFishes();
List<T>
टी पर दोनों में- और आउट-दिशाएं हैं, इसलिए यह न तो सह-संस्करण है और न ही गर्भ-संस्करण है, लेकिन एक इंटरफ़ेस जो आपको वस्तुओं को जोड़ने की अनुमति देता है, जैसे:
interface IWriteOnlyList<in T>
{
void Add(T value);
}
आपको ऐसा करने की अनुमति देगा:
IWriteOnlyList<Fish> fishes = GetWriteAccessToAnimals();
IWriteOnlyList<Animal>
fishes.Add(new Fish("Guppy")); <-- this is now safe
यहाँ कुछ वीडियो हैं जो अवधारणाओं को दिखाते हैं:
यहाँ एक उदाहरण है:
namespace SO2719954
{
class Base { }
class Descendant : Base { }
interface IBibbleOut<out T> { }
interface IBibbleIn<in T> { }
class Program
{
static void Main(string[] args)
{
IBibbleOut<Base> b = GetOutDescendant();
IBibbleIn<Descendant> d = GetInBase();
}
static IBibbleOut<Descendant> GetOutDescendant()
{
return null;
}
static IBibbleIn<Base> GetInBase()
{
return null;
}
}
}
इन चिह्नों के बिना, निम्नलिखित संकलन कर सकता है:
public List<Descendant> GetDescendants() ...
List<Base> bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant
या यह:
public List<Base> GetBases() ...
List<Descendant> descendants = GetBases(); <-- uh-oh, we try to treat all Bases
as Descendants