दिलचस्प पोस्ट
स्पार्क – लोड करें CSV फ़ाइल को डेटाफ़्रेम के रूप में? कैसे करता है? ~ (टिल्ड / बैंग बैंग टिल्ड नहीं) एक 'शामिल / शामिल' अर्रे विधि कॉल के परिणाम को बदलते हैं? Geom_point में लेबल अंक पायथन में अधिकतम फ्लोट क्या है? जावास्क्रिप्ट वादों के लिए सही शब्दावली क्या है <XMP> टैग के लिए क्या इस्तेमाल किया गया था? अजैव फ़्लोटिंग नंबर लैंडस्केप में UIImagePickerController ओएस एक्स पर पायथन और ओपनएसएसएल संस्करण संदर्भ मुद्दा प्रोग्रामात्मक रूप से स्तंभ और पंक्तियों को WPF Datagrid जोड़ें साझा वरीयता में एक क्लास ऑब्जेक्ट को स्टोर और पुनः प्राप्त करें अनिर्धारित प्रतीकों "के लिए vtable …" और "प्रकार के लिए …" … मैं कैसे जांचूं कि वस्तु में जावास्क्रिप्ट में एक संपत्ति है? String.split पाइप सीमांकक को बचने की आवश्यकता क्यों है? संपादन टेक्स्ट के लिए कस्टम कट / प्रतिलिपि एक्शन बार जो टेक्स्ट चयन हैंडल दिखाता है

संप्रभु और असली दुनिया उदाहरण contravariance

मुझे समझ में थोड़ा परेशानी हो रही है कि मैं वास्तविक दुनिया में कैसे सहानुभूति और भ्रष्टाचार का प्रयोग करूंगा।

अब तक, मैंने देखा है कि केवल उदाहरण एक ही पुरानी सरणी उदाहरण हैं।

object[] objectArray = new string[] { "string 1", "string 2" }; 

यह एक उदाहरण देखने के लिए अच्छा होगा जो मुझे अपने विकास के दौरान इसका उपयोग करने की इजाजत देगी यदि मैं देख सकता हूं कि इसे कहीं और इस्तेमाल किया जा रहा है।

वेब के समाधान से एकत्रित समाधान "संप्रभु और असली दुनिया उदाहरण contravariance"

मान लें कि आपके पास एक क्लास व्यक्ति और एक क्लास है जो कि उसमें से आता है, शिक्षक आपके पास कुछ परिचालन हैं जो एक IEnumerable<Person> तर्क के रूप में लेते हैं। आपके स्कूल कक्षा में आपके पास एक ऐसा तरीका है जो एक IEnumerable<Teacher> देता है सहकारिता आपको कम व्युत्पन्न (अधिक सामान्य) प्रकार के लिए अधिक व्युत्पन्न प्रकार को प्रतिस्थापित करने वाले तरीकों के लिए सीधे उस परिणाम का उपयोग करने की अनुमति देता है; विपरीत, काउंटर-इंटिविटिव, आपको अधिक सामान्य प्रकार का उपयोग करने की अनुमति देता है, जहां अधिक व्युत्पन्न प्रकार निर्दिष्ट हैं। यह भी https://msdn.microsoft.com/en-us/library/dd799517.aspx देखें

 public class Person { public string Name { get; set; } } public class Teacher : Person { } public class MailingList { public void Add(IEnumerable<out Person> people) { ... } } public class School { public IEnumerable<Teacher> GetTeachers() { ... } } public class PersonNameComparer : IComparer<Person> { public int Compare(Person a, Person b) { if (a == null) return b == null ? 0 : -1; return b == null ? 1 : Compare(a,b); } private int Compare(string a, string b) { if (a == null) return b == null ? 0 : -1; return b == null ? 1 : a.CompareTo(b); } } ... var teachers = school.GetTeachers(); var mailingList = new MailingList(); // Add() is covariant, we can use a more derived type mailingList.Add(teachers); // the Set<T> constructor uses a contravariant interface, IComparer<T>, // we can use a more generic type than required. See https://msdn.microsoft.com/en-us/library/8ehhxeaf.aspx for declaration syntax var teacherSet = new SortedSet<Teachers>(teachers, new PersonNameComparer()); 
 // Contravariance interface IGobbler<in T> { void gobble(T t); } // Since a QuadrupedGobbler can gobble any four-footed // creature, it is OK to treat it as a donkey gobbler. IGobbler<Donkey> dg = new QuadrupedGobbler(); dg.gobble(MyDonkey()); // Covariance interface ISpewer<out T> { T spew(); } // A MouseSpewer obviously spews rodents (all mice are // rodents), so we can treat it as a rodent spewer. ISpewer<Rodent> rs = new MouseSpewer(); Rodent r = rs.spew(); 

संपूर्णता के लिए…

 // Invariance interface IHat<T> { void hide(T t); T pull(); } // A RabbitHat… IHat<Rabbit> rHat = RabbitHat(); // …cannot be treated covariantly as a mammal hat… IHat<Mammal> mHat = rHat; // Compiler error // …because… mHat.hide(new Dolphin()); // Hide a dolphin in a rabbit hat?? // It also cannot be treated contravariantly as a cottontail hat… IHat<CottonTail> cHat = rHat; // Compiler error // …because… rHat.hide(new MarshRabbit()); cHat.pull(); // Pull a marsh rabbit out of a cottontail hat?? 

अंतर को समझने में मेरी सहायता करने के लिए यहां जो कुछ इकट्ठा किया गया है वह है I

 public interface ICovariant<out T> { } public interface IContravariant<in T> { } public class Covariant<T> : ICovariant<T> { } public class Contravariant<T> : IContravariant<T> { } public class Fruit { } public class Apple : Fruit { } public class TheInsAndOuts { public void Covariance() { ICovariant<Fruit> fruit = new Covariant<Fruit>(); ICovariant<Apple> apple = new Covariant<Apple>(); Covariant(fruit); Covariant(apple); //apple is being upcasted to fruit, without the out keyword this will not compile } public void Contravariance() { IContravariant<Fruit> fruit = new Contravariant<Fruit>(); IContravariant<Apple> apple = new Contravariant<Apple>(); Contravariant(fruit); //fruit is being downcasted to apple, without the in keyword this will not compile Contravariant(apple); } public void Covariant(ICovariant<Fruit> fruit) { } public void Contravariant(IContravariant<Apple> apple) { } } 

tldr

 ICovariant<Fruit> apple = new Covariant<Apple>(); //because it's covariant IContravariant<Apple> fruit = new Contravariant<Fruit>(); //because it's contravariant 

इन-आउट कीवर्ड कंपाइलर का कास्टिंग नियम इंटरफेस और जेनेटिक पैरामीटर वाले प्रतिनिधियों के लिए नियंत्रित करते हैं:

 interface IInvariant<T> { // This interface can not be implicitly cast AT ALL // Used for non-readonly collections IList<T> GetList { get; } // Used when T is used as both argument *and* return type T Method(T argument); }//interface interface ICovariant<out T> { // This interface can be implicitly cast to LESS DERIVED (upcasting) // Used for readonly collections IEnumerable<T> GetList { get; } // Used when T is used as return type T Method(); }//interface interface IContravariant<in T> { // This interface can be implicitly cast to MORE DERIVED (downcasting) // Usually means T is used as argument void Method(T argument); }//interface class Casting { IInvariant<Animal> invariantAnimal; ICovariant<Animal> covariantAnimal; IContravariant<Animal> contravariantAnimal; IInvariant<Fish> invariantFish; ICovariant<Fish> covariantFish; IContravariant<Fish> contravariantFish; public void Go() { // NOT ALLOWED invariants do *not* allow implicit casting: invariantAnimal = invariantFish; invariantFish = invariantAnimal; // NOT ALLOWED // ALLOWED covariants *allow* implicit upcasting: covariantAnimal = covariantFish; // NOT ALLOWED covariants do *not* allow implicit downcasting: covariantFish = covariantAnimal; // NOT ALLOWED contravariants do *not* allow implicit upcasting: contravariantAnimal = contravariantFish; // ALLOWED contravariants *allow* implicit downcasting contravariantFish = contravariantAnimal; }//method }//class // .NET Framework Examples: public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable { } public interface IEnumerable<out T> : IEnumerable { } class Delegates { // When T is used as both "in" (argument) and "out" (return value) delegate T Invariant<T>(T argument); // When T is used as "out" (return value) only delegate T Covariant<out T>(); // When T is used as "in" (argument) only delegate void Contravariant<in T>(T argument); // Confusing delegate T CovariantBoth<out T>(T argument); // Confusing delegate T ContravariantBoth<in T>(T argument); // From .NET Framework: public delegate void Action<in T>(T obj); public delegate TResult Func<in T, out TResult>(T arg); }//class 
 class A {} class B : A {} public void SomeFunction() { var someListOfB = new List<B>(); someListOfB.Add(new B()); someListOfB.Add(new B()); someListOfB.Add(new B()); SomeFunctionThatTakesA(someListOfB); } public void SomeFunctionThatTakesA(IEnumerable<A> input) { // Before C# 4, you couldn't pass in List<B>: // cannot convert from // 'System.Collections.Generic.List<ConsoleApplication1.B>' to // 'System.Collections.Generic.IEnumerable<ConsoleApplication1.A>' } 

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

बस एक जाल के बारे में आपको चेतावनी देने के लिए:

 var ListOfB = new List<B>(); if(ListOfB is IEnumerable<A>) { // In C# 4, this branch will // execute... Console.Write("It is A"); } else if (ListOfB is IEnumerable<B>) { // ...but in C# 3 and earlier, // this one will execute instead. Console.Write("It is B"); } 

यह भयानक कोड है, लेकिन यह अस्तित्व में है और सी # 4 में बदलते व्यवहार सूक्ष्म और मुश्किल से मिल सकता है यदि आप इस तरह से एक निर्माण का उपयोग करें बग खोजने के लिए

एमएसडीएन से

निम्न कोड उदाहरण विधि समूहों के लिए सहानुभूति और भ्रष्ट समर्थन दिखाते हैं

 static object GetObject() { return null; } static void SetObject(object obj) { } static string GetString() { return ""; } static void SetString(string str) { } static void Test() { // Covariance. A delegate specifies a return type as object, // but you can assign a method that returns a string. Func<object> del = GetString; // Contravariance. A delegate specifies a parameter type as string, // but you can assign a method that takes an object. Action<string> del2 = SetObject; } 

यहां एक विरासत पदानुक्रम का उपयोग करते हुए एक सरल उदाहरण है

सहप्रसरण

सह प्रकार का अपरिवर्तनीय संग्रह के साथ व्यापक रूप से उपयोग किया जाता है (यानी जहां नए तत्व को संग्रह से जोड़ा या निकाला नहीं जा सकता)

साधारण वर्ग पदानुक्रम को देखते हुए:

 public abstract class LifeForm { } public abstract class Animal : LifeForm { } public class Giraffe : Animal { } public class Zebra : Animal { } 

प्रतीत होता है, इस तरह एक विधि के रूप में

 public static void DoSomethingWithLifeForms(IList<LifeForm> lifeForms) { foreach (var lifeForm in lifeForms) { Console.WriteLine(lifeForm.GetType().ToString()); } } 

… एक विषम संग्रह को स्वीकार करना चाहिए (जो यह करता है)

 var myAnimals = new List<LifeForm> { new Giraffe(), new Zebra() }; DoSomethingWithLifeForms(myAnimals); // Giraffe, Zebra 

हालांकि, एक अधिक व्युत्पन्न प्रकार का संग्रह विफल रहता है!

 var myGiraffes = new List<Giraffe> { new Giraffe(), // "Jerry" new Giraffe() // "Melman" }; DoSomethingWithLifeForms(myGiraffes); // Compile Error! 

cannot convert from 'System.Collections.Generic.List<Giraffe>' to 'System.Collections.Generic.IList<LifeForm>'

क्यूं कर? क्योंकि सामान्य पैरामीटर IList<LifeForm> संप्रदाय नहीं है – IList<LifeForm> अपरिवर्तनीय है, और केवल संग्रह को स्वीकार करता है (जो LifeForm को लागू करता है) जहां पैरामीटर वाला टाइप T को LifeForm होना चाहिए

अगर मैं दुर्भावनापूर्ण रूप से विधि का कार्यान्वयन बदलता है (लेकिन उसी विधि हस्ताक्षर को छोड़ दें), कारण संकलक को List<Giraffe> को रोकना रोकता है स्पष्ट हो जाता है:

  public static void DoSomethingWithLifeForms(IList<LifeForm> lifeForms) { lifeForms.Add(new Zebra()); } 

चूंकि IList तत्वों को जोड़ने या हटाने के लिए, LifeForm किसी भी उपवर्ग को पैरामीटर lifeForms जोड़ा जा सकता है, और विधि से पारित व्युत्पन्न प्रकारों के किसी भी संग्रह के प्रकार का उल्लंघन होगा। (यहां, दुर्भावनापूर्ण तरीके से Zebra को var myGiraffes ) सौभाग्य से, कंपाइलर हमें इस खतरे से बचाता है।

इसका समाधान यह सुनिश्चित करना है कि एक संप्रदाय सामान्य प्रकार का उपयोग किया जाता है, जैसे IEnumerable ( IEnumerable<out T> रूप में परिभाषित)। यह संग्रह में परिवर्तन को रोकता है, और परिणामस्वरूप, LifeForm उपप्रकार के साथ कोई भी संग्रह अब विधि को पारित किया जा सकता है:

 public static void DoSomethingWithLifeForms(IEnumerable<LifeForm> lifeForms) { foreach (var lifeForm in lifeForms) { Console.WriteLine(lifeForm.GetType().ToString()); } } 

DoSomethingWithLifeForms() अब Zebras , Giraffes और LifeForm किसी भी LifeForm साथ कहा जा सकता है

contravariance

अक्सर जब प्रथाओं को पैरामीटर के रूप में पारित किया जाता है, तो अक्सर क्रांतिकारी का उपयोग किया जाता है

यहां एक फ़ंक्शन का एक उदाहरण है, जो एक पैरामीटर के रूप में Action<Zebra> लेता है, और इसे ज़ेबरा के एक ज्ञात उदाहरण पर आमंत्रित करता है:

 public void PerformZebraAction(Action<Zebra> zebraAction) { var zebraToAction = new Zebra(); zebraAction(zebraToAction); } 

अपेक्षित रूप से, यह सिर्फ ठीक काम करता है:

 var myAction = new Action<Zebra>(z => Console.WriteLine("I'm a zebra")); PerformZebraAction(myAction); // I'm a zebra 

Intuitively, यह विफल हो जाएगा:

 var myAction = new Action<Giraffe>(g => Console.WriteLine("I'm a giraffe")); PerformZebraAction(myAction); 

cannot convert from 'System.Action<Giraffe>' to 'System.Action<Zebra>'

हालांकि, यह सफल होता है

 var myAction = new Action<Animal>(a => Console.WriteLine("I'm an animal")); PerformZebraAction(myAction); // I'm an animal 

और यहां तक ​​कि यह भी सफल होता है:

 var myAction = new Action<object>(a => Console.WriteLine("I'm an amoeba")); PerformZebraAction(myAction); // I'm an amoeba 

क्यूं कर? क्योंकि Action को Action<in T> रूप में परिभाषित किया गया है, अर्थात् यह contravariant

यद्यपि यह पहली बार में अनजान हो सकता है (उदाहरण के लिए, Action<object> Action<Zebra> जरूरी पैरामीटर के रूप में कैसे पारित किया जा सकता है? Action<Zebra> ?), यदि आप कदमों को PerformZebraAction , तो आप ध्यान दें कि फ़ंक्शन ( PerformZebraAction ) ही जिम्मेदार है समारोह के लिए Zebra उदाहरण को पारित करने के लिए, और कॉलिंग कोड नहीं।

इस तरीके से उच्चतर क्रम कार्यों का उपयोग करने के व्युत्क्रम दृष्टिकोण की वजह से, जब तक कि Action को लागू किया जाता है, यह ज़्यादा व्युत्पन्न ऑब्जेक्ट उदाहरण होता है जिसे zebraAction फंक्शन (एक पैरामीटर के रूप में पारित) के खिलाफ लगाया जाता है, जो स्वयं कम व्युत्पन्न प्रकार का उपयोग करता है ।

कनवर्टर प्रतिनिधि मुझे एक साथ काम करने वाली दोनों अवधारणाओं को कल्पना करने में मदद करता है:

 delegate TOutput Converter<in TInput, out TOutput>(TInput input); 

TOutput प्रतिनिधित्व करता है जहां एक विधि अधिक विशिष्ट प्रकार देता है

TInput प्रतिनिधित्व करता है जहां एक विधि एक कम विशिष्ट प्रकार पारित की जाती है।

 public class Dog { public string Name { get; set; } } public class Poodle : Dog { public void DoBackflip(){ System.Console.WriteLine("2nd smartest breed - woof!"); } } public static Poodle ConvertDogToPoodle(Dog dog) { return new Poodle() { Name = dog.Name }; } List<Dog> dogs = new List<Dog>() { new Dog { Name = "Truffles" }, new Dog { Name = "Fuzzball" } }; List<Poodle> poodles = dogs.ConvertAll(new Converter<Dog, Poodle>(ConvertDogToPoodle)); poodles[0].DoBackflip();