সমবায়তা এবং বৈপরীত্য বাস্তব বিশ্বের উদাহরণ


162

আসল বিশ্বে কীভাবে সাম্প্রদায়িকতা এবং বৈপরীত্য ব্যবহার করব তা বুঝতে আমার একটু সমস্যা হচ্ছে।

এখনও অবধি, আমি যে উদাহরণগুলি দেখেছি সেগুলি একই পুরানো অ্যারে উদাহরণ।

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

এমন উদাহরণটি দেখতে পারা ভাল লাগবে যা আমার বিকাশের সময় এটির ব্যবহারের অনুমতি দেয় যদি আমি এটি অন্য কোথাও ব্যবহার করা দেখতে পেতাম।


1
আমি অন্বেষণ সহভেদাংক এই উত্তর : (আমার নিজের) প্রশ্নের সহভেদাংক প্রকারসমূহ: উদাহরণ দ্বারা । আমি মনে করি আপনি এটি আকর্ষণীয় এবং আশাবাদী শিক্ষাদানকারী পাবেন।
ক্রিশ্চিয়ান ডায়াকোনস্কু

উত্তর:


109

ধরা যাক আপনার কাছে একটি শ্রেনী ব্যক্তি এবং এটি থেকে উদ্ভূত একটি শ্রেণি রয়েছে, শিক্ষক। আপনার কিছু অপারেশন রয়েছে যা IEnumerable<Person>যুক্তি হিসাবে গ্রহণ করে। আপনার স্কুল ক্লাসে আপনার একটি পদ্ধতি রয়েছে যা ফেরত দেয় IEnumerable<Teacher>। কোভারিয়েন্স আপনাকে সেই ফলাফলগুলি সরাসরি ব্যবহার করতে দেয় যেগুলি গ্রহণ করে IEnumerable<Person>, কম উত্পন্ন (আরও জেনেরিক) প্রকারের জন্য আরও উদ্ভূত প্রকারকে প্রতিস্থাপন করে take স্ববিরোধী, পাল্টা স্বজ্ঞাতভাবে, আপনাকে আরও জেনেরিক ধরণের ব্যবহার করতে দেয়, যেখানে আরও উত্পন্ন উত্স নির্ধারিত হয়।

এমএসডিএন-তে জেনারিক্সে কোভারিয়েন্স এবং কনট্রাভারিয়েন্সটি দেখুন ।

শ্রেণি :

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<in 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());

14
@ ফিলিপবার্টুজি - যদি এই উত্তরটি লেখার সময় আমার মতো হয়, আপনি এমন একটি বিশ্ববিদ্যালয়ে নিযুক্ত ছিলেন যা একটি বাস্তব বিশ্বের উদাহরণ।
tvanfosson

5
যখন এটি প্রশ্নের উত্তর না দেয় এবং সি # তে কো / কনট্রাস্ট ভেরিয়েন্স ব্যবহারের কোনও উদাহরণ দেয় না তবে কীভাবে এটির উত্তর চিহ্নিত করা যায়?
বারাকাকাফ

@ বারাককাফ বিপরীতের একটি উদাহরণ যুক্ত করেছেন। আপনি কেন কোয়ারিয়েন্সের উদাহরণটি দেখছেন না তা নিশ্চিত নন - সম্ভবত আপনার কোডটি নীচে স্ক্রোল করার দরকার ছিল - তবে আমি এর আশেপাশে কিছু মন্তব্য যুক্ত করেছি।
tvanfosson

@ ট্যানফোসন কোডটি সহ / বিপরীতে ব্যবহার করেছে, আমি জানি যে এটি কীভাবে এটি ঘোষণা করবেন তা দেখায় না। উদাহরণটি জেনেরিক ঘোষণায় ইন / আউট ব্যবহার দেখায় না যখন অন্য উত্তরটি দেয়।
বারাকাকাফ

সুতরাং, যদি আমি এটি সঠিকভাবে পাই তবে Covariance যা সি # তে লিসকভের প্রতিস্থাপনের নীতিটিকে মঞ্জুরি দেয়, তা কি ঠিক?
মিগুয়েল ভেলোসো

136
// 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??

138
আমি এই বাস্তব উদাহরণ পছন্দ করি। আমি গত সপ্তাহে কিছু গাধা গাবলিং কোড লিখছিলাম এবং আমি এতই আনন্দিত যে এখন আমাদের সম্প্রদায় রয়েছে। :-)
এরিক লিপার্ট

4
উপরের এই মন্তব্যটি @ জাভাদ্বা দ্য এরিলিপ্পার্টকে বলছেন যে সমবায়িতা এবং বিপরীতমুখীতা আমার গ্র্যান্ডিকে কীভাবে ডিম চুষতে হয় তা বলার একটি বাস্তববাদী সমবায় উদাহরণ! : p
iAteABug_And_iLiked_it

1
প্রশ্নটি জিজ্ঞাসা করেনি যে বৈপরীত্য এবং সমবায় কী করতে পারে , এটি আপনাকে কেন এটি ব্যবহারের প্রয়োজন হবে তা জিজ্ঞাসা করেছিল । আপনার উদাহরণ ব্যবহারিক থেকে অনেক দূরে কারণ এটিরও প্রয়োজন হয় না। আমি একটি চতুর্ভুজযুক্ত গাব্বলার তৈরি করতে এবং এটি নিজেকে হিসাবে বিবেচনা করতে পারি (এটি আইগোব্লার <কেচারুপড> এ নিয়োগ করুন) এবং এটি এখনও গাধাগুলিকে গর্ব করতে পারে (আমি একটি গাধাকে গাব্বল পদ্ধতিতে প্রবেশ করতে পারি যার জন্য একটি চতুর্থাংশের প্রয়োজন)। কোনও বৈপরীত্যের দরকার নেই। এটি দুর্দান্ত যে আমরা একটি চতুর্ভুজগ্রাহককে গাধা গব্বলারের মতো আচরণ করতে পারি, তবে এই ক্ষেত্রে, যদি একটি চতুর্থাংশ গাবলার ইতিমধ্যে গাধাগুলি গাধাগুলি করতে পারে তবে আমাদের কেন দরকার হবে?
তারযুক্ত_ই

1
@ ওয়্যার্ড_ইন কারণ আপনি যখন কেবল গাধা সম্পর্কে যত্নশীল হন, তখন সাধারণ হয়ে আরও বেশি কিছু পেতে পারেন। উদাহরণস্বরূপ, যদি আপনার কাছে এমন একটি খামার রয়েছে যা গাধাগুলি ছড়িয়ে দেওয়ার জন্য গাধা সরবরাহ করে তবে আপনি এটি হিসাবে প্রকাশ করতে পারেন void feed(IGobbler<Donkey> dg)। আপনি যদি এর পরিবর্তে একটি আইজিব্লার <কৌদ্রুপ>> প্যারামিটার হিসাবে গ্রহণ করেন তবে আপনি এমন ড্রাগনে যেতে পারবেন না যা কেবল গাধা খায়।
মার্সেলো ক্যান্টোস

1
পার্টি দেরীতে ওয়াহে, তবে এটি এসও এর আশেপাশে আমি দেখেছি সেরা লিখিত উদাহরণ। হাস্যকর হওয়ার সময় সম্পূর্ণ জ্ঞান অর্জন করে। আমি উত্তর দিয়ে আমার গেমটি খেলতে যাচ্ছি ...
জেসি উইলিয়ামস

120

পার্থক্যটি বুঝতে সাহায্য করার জন্য আমি এখানে যা রেখেছি তা এখানে

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

10
আমি এ পর্যন্ত সেরা জিনিসটি দেখেছি এটি পরিষ্কার এবং সংক্ষিপ্ত। দুর্দান্ত উদাহরণ!
রব এল

6
ফলটি কীভাবে আপেলকে নীচে নামানো যায় ( Contravarianceউদাহরণস্বরূপ) যখন Fruitএর পিতামাতা হয় Apple?
টোবিয়াস মার্চচাল

@TobiasMarschall আপনি "পলিমরফিজম" উপর আরো বেশি পড়াশোনা করতে আছে মানে
SNR

56

ইন-আউট কীওয়ার্ডগুলি জেনেরিক পরামিতিগুলির সাথে ইন্টারফেস এবং প্রতিনিধিদের জন্য সংকলকটির কাস্টিং বিধিগুলি নিয়ন্ত্রণ করে:

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

ধরে নেওয়া মাছটি প্রাণীর একটি উপপ্রকার pe উপায় দ্বারা দুর্দান্ত উত্তর।
রাজন প্রসাদ

48

উত্তরাধিকারের শ্রেণিবিন্যাস ব্যবহার করে এখানে একটি সাধারণ উদাহরণ।

সাধারণ শ্রেণীর শ্রেণিবিন্যাস দেওয়া:

এখানে চিত্র বর্ণনা লিখুন

এবং কোডে:

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

Invariance (অর্থাত জেনেরিক টাইপ পরামিতি * নয় * দিয়ে সাজানো inবা outকিওয়ার্ড)

আপাতদৃষ্টিতে, এর মতো একটি পদ্ধতি

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

... একটি ভিন্নধর্মী সংগ্রহ গ্রহণ করা উচিত: (যা এটি করে)

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

যাইহোক, আরও উদ্ভূত প্রকারের সংগ্রহটি ব্যর্থ হয়!

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

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

কেন? যেহেতু জেনেরিক প্যারামিটারটি IList<LifeForm>কোভারিয়েন্ট নয় - IList<T>এটি অবিচলিত, তাই IList<LifeForm>কেবলমাত্র সংগ্রহগুলি গ্রহণ করে (যা IList বাস্তবায়ন করে) যেখানে প্যারামিটারাইজড ধরণ Tথাকতে হবেLifeForm

যদি পদ্ধতিটির প্রয়োগটি PrintLifeFormsদূষিত হয় (তবে একই পদ্ধতিটির স্বাক্ষর রয়েছে), সংকলকটি কেন বাধা দেয় তা List<Giraffe>স্পষ্ট হয়ে যায়:

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

যেহেতু IListউপাদানগুলি যুক্ত বা অপসারণের অনুমতি দেয়, সুতরাং যে কোনও সাবক্লাস LifeFormএইভাবে প্যারামিটারে যুক্ত করা যেতে পারে lifeFormsএবং পদ্ধতিতে পাস হওয়া কোনও সংগ্রহিত ধরণের লঙ্ঘন করবে। (এখানে, দূষিত পদ্ধতি যোগ করার চেষ্টা করবে Zebraকরার var myGiraffes)। ভাগ্যক্রমে, সংকলক আমাদের এই বিপদ থেকে রক্ষা করে।

কোভারিয়েন্স (প্যারামিটারাইজড টাইপের সাথে জেনেরিক দিয়ে সজ্জিত out)

কোভারিয়েন্স অপরিবর্তনীয় সংগ্রহের সাথে ব্যাপকভাবে ব্যবহৃত হয় (যেমন যেখানে কোনও সংগ্রহ থেকে নতুন উপাদান যুক্ত বা সরানো যায় না)

উপরের উদাহরণের সমাধানটি হল যে কোনও সমবায়ু জেনেরিক সংগ্রহের ধরণ ব্যবহৃত হয়েছে তা নিশ্চিত করা IEnumerable( যেমন সংজ্ঞায়িত IEnumerable<out T>)। IEnumerableসংগ্রহে পরিবর্তনের কোনও পদ্ধতি নেই এবং প্রচলিত ফলাফলের ফলে outসাব - টাইপ সহ যে কোনও সংগ্রহ LifeFormএখন পদ্ধতিতে পাস করা যেতে পারে:

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

PrintLifeFormsএখন বলা যেতে পারে Zebras, Giraffesএবং কোন IEnumerable<>কোন উপশ্রেণী এরLifeForm

কনট্রাভারিয়েন্স (প্যারামিটারাইজড টাইপের সাথে জেনেরিক দিয়ে সজ্জিত in )

পরামিতি হিসাবে ফাংশনগুলি পাস করার সময় কনট্রাভারিয়েন্স প্রায়শই ব্যবহৃত হয়।

এখানে কোনও ফাংশনের উদাহরণ রয়েছে, যা Action<Zebra>প্যারামিটার হিসাবে গ্রহণ করে এবং এটি একটি জেব্রা সম্পর্কিত একটি পরিচিত উদাহরণে প্রার্থনা করে:

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

যেমনটি প্রত্যাশিত, এটি ঠিক কাজ করে:

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

স্বজ্ঞাতভাবে, এটি ব্যর্থ হবে:

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

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

তবে, এটি সফল হয় eds

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<Zebra> myActionএটি myAction"সর্বাধিক" এ হতে পারে Action<Zebra>, তবে এর থেকে কম উত্পন্ন চশমাZebra গ্রহণযোগ্য।

যদিও এটি প্রথমে অ-স্বজ্ঞাত হতে পারে (যেমন Action<object>কোনও পরামিতিগুলির প্রয়োজনীয় হিসাবে কীভাবে পাস করা যায় Action<Zebra>?), আপনি যদি পদক্ষেপগুলি আনপ্যাক করেন তবে আপনি খেয়াল করবেন যে কথিত ফাংশনটি PerformZebraActionনিজেই ডেটা পাস করার জন্য দায়বদ্ধ (এই ক্ষেত্রে একটিZebra উদাহরণস্বরূপ) ) ফাংশনে - ডেটিং কলিং কোড থেকে আসে না।

এই পদ্ধতিতে উচ্চতর অর্ডার ফাংশনগুলি ব্যবহার করার বিপরীত পদ্ধতির কারণে, যখন সময়টি Actionআহ্বান করা হয় ততক্ষণে এটি আরও উদ্ভূত Zebraউদাহরণ যা zebraActionফাংশনের বিপরীতে ডাকা হয় (প্যারামিটার হিসাবে পাস করা হয়), যদিও ফাংশনটি নিজেই একটি কম উত্পন্ন ধরণের ব্যবহার করে uses


7
এটি বিভিন্ন বৈকল্পিক বিকল্পগুলির জন্য একটি দুর্দান্ত ব্যাখ্যা, যেহেতু এটি উদাহরণের মাধ্যমে কথা বলে এবং সংকলক কেন / আউট কীওয়ার্ড ছাড়াই নিষিদ্ধ বা অনুমতি দেয়
স্পষ্ট

কোথায় inশব্দ জন্য ব্যবহৃত contravariance ?
জাভাদবা

উপরের @ জাভাদ্বা, Action<in T>এবং Func<in T, out TResult>ইনপুট ধরণের মধ্যে বিপরীত রয়েছে। (আমার উদাহরণগুলিতে বিদ্যমান ইনগ্রান্ট (তালিকা), কোভেরিয়েন্ট (আইনিউমেবল) এবং কনট্রোভারেন্ট (অ্যাকশন,
ফানক

ঠিক আছে আমি এটা C#না জানি না।
জাভদ্বা

এটি স্কালায় মোটামুটি একইরকম, কেবল আলাদা সিনট্যাক্স - [+ টি] টিতে সমবায় হবে, [-টি] টি তে বিপরীতমুখী হবে, স্কালাও 'সীমাবদ্ধতা' এবং 'কিছুই না' প্রমিসিউস সাবক্লাসকে কার্যকর করতে পারে, যা সি # নেই
স্টুয়ার্টলসি

32
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-তে পরিবর্তিত আচরণ সূক্ষ্ম এবং শক্তির সাথে পরিচয় করিয়ে দিতে পারে যদি আপনি এইরকম কোনও নির্মাণ ব্যবহার করেন তবে বাগগুলি খুঁজে পাওয়া শক্ত।


সুতরাং এটি কোনও কিছুর চেয়ে সংগ্রহগুলিকে আরও বেশি প্রভাবিত করে, কারণ সি # 3 এ আপনি আরও উত্পন্ন ধরণের প্রকারটি কম প্রাপ্ত উত্পন্ন প্রকারের পদ্ধতিতে পাস করতে পারেন।
রেজার

3
হ্যাঁ, বড় পরিবর্তনটি হ'ল আইমনামেবল এখন এটি সমর্থন করে, যেখানে এটি আগে হয়নি।
মাইকেল Stum

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;
}

4

Contravariance

প্রকৃত বিশ্বে আপনি খরগোশের আশ্রয়ের পরিবর্তে সর্বদা প্রাণীর জন্য একটি আশ্রয় ব্যবহার করতে পারেন কারণ যতবারই কোনও প্রাণী আশ্রয় একটি খরগোশকে হোস্ট করে এটি একটি প্রাণী। তবে, আপনি যদি কোনও প্রাণীর আশ্রয়ের পরিবর্তে খরগোশের আশ্রয় ব্যবহার করেন তবে তার কর্মীরা বাঘের কাছে খেতে পারবেন।

কোড দাঁড়াচ্ছে এই যে, যে আপনি একটি আছে যদি IShelter<Animal> animalsআপনি কেবল লিখতে পারেন IShelter<Rabbit> rabbits = animals যদি তোমাকে কথা দিচ্ছি এবং ব্যবহারের Tমধ্যে IShelter<T>পদ্ধতি পরামিতি তাই মত শুধুমাত্র হিসাবে:

public class Contravariance
{
    public class Animal { }
    public class Rabbit : Animal { }

    public interface IShelter<in T>
    {
        void Host(T thing);
    }

    public void NoCompileErrors()
    {
        IShelter<Animal> animals = null;
        IShelter<Rabbit> rabbits = null;

        rabbits = animals;
    }
}

এবং একটি আরো জেনেরিক এক সঙ্গে একটি আইটেম প্রতিস্থাপন, অর্থাত্ ভ্যারিয়েন্স হ্রাস বা পরিচয় করিয়ে বিরূদ্ধে ভ্যারিয়েন্স।

সহভেদাংক

বাস্তব বিশ্বে আপনি সর্বদা প্রাণী সরবরাহকারী পরিবর্তে খরগোশের সরবরাহকারী ব্যবহার করতে পারেন কারণ প্রতিবার যখন খরগোশ সরবরাহকারী আপনাকে খরগোশ দেয় এটি একটি প্রাণী। তবে, আপনি খরগোশের সরবরাহকারীর পরিবর্তে যদি কোনও প্রাণী সরবরাহকারী ব্যবহার করেন তবে আপনি একটি বাঘের দ্বারা খাওয়া যেতে পারেন।

কোডে, এর অর্থ হ'ল যদি আপনার কাছে থাকে তবে আপনি যদি ISupply<Rabbit> rabbitsকেবল প্রতিশ্রুতি দেন এবং কেবল পদ্ধতি পদ্ধতি ফেরতের মান হিসাবে ব্যবহার করেন তবে ISupply<Animal> animals = rabbits তা লিখতে পারেন :TISupply<T>

public class Covariance
{
    public class Animal { }
    public class Rabbit : Animal { }

    public interface ISupply<out T>
    {
        T Get();
    }

    public void NoCompileErrors()
    {
        ISupply<Animal> animals = null;
        ISupply<Rabbit> rabbits = null;

        animals = rabbits;
    }
}

এবং একটি আইটেমকে আরও উত্পন্ন একের সাথে প্রতিস্থাপন করুন, যেমন বৈকল্পিক বৃদ্ধি করুন বা কো প্রবর্তন করুন বৈকল্পিক ।

সব মিলিয়ে এটি কেবল একটি সংকলন-সময় যাচাইযোগ্য এটি আপনার কাছ থেকে প্রতিশ্রুতি যে আপনি ধরণের সুরক্ষা বজায় রাখতে এবং কাউকে খাওয়া না পাওয়ার জন্য একটি জেনেরিক ধরণের একটি নির্দিষ্ট ফ্যাশনে আচরণ করবেন।

আপনি এটিকে আপনার চারপাশে আপনার মাথাটি দু'বার মুড়িয়ে দিতে একটি পড়তে দিতে পারেন ।


আপনি একটি বাঘ দ্বারা খাওয়া যেতে পারে যে
উপচে পড়া

আপনার মন্তব্য contravarianceআকর্ষণীয়। আমি এটিতে একটি অপারেশনাল প্রয়োজনীয়তার ইঙ্গিত হিসাবে এটি পড়ছি : যে আরও সাধারণ ধরণের অবশ্যই এটি থেকে প্রাপ্ত সমস্ত ধরণের ব্যবহারের ক্ষেত্রে সমর্থন করে। সুতরাং এক্ষেত্রে পশুর আশ্রয় অবশ্যই প্রতিটি প্রাণীর আশ্রয়কেন্দ্রকে সমর্থন করতে সক্ষম হবে। সেক্ষেত্রে একটি নতুন সাবক্লাস যুক্ত করা সুপারক্লাসটি ভেঙে দিতে পারে! এটি হ'ল - আমরা যদি উপ-প্রকার টাইরনোসরাস রেক্স যুক্ত করি তবে এটি আমাদের বিদ্যমান প্রাণী আশ্রয় নষ্ট করতে পারে ।
জাভাদবা

(চলছে)। এটি কাঠামোগতভাবে পরিষ্কারভাবে বর্ণিত সমবায় থেকে তীব্রভাবে পৃথক : আরও সমস্ত নির্দিষ্ট উপ-প্রকারগুলি সুপার টাইপের সংজ্ঞায়িত ক্রিয়াকলাপগুলিকে সমর্থন করে - তবে প্রয়োজনীয়ভাবে একই পদ্ধতিতে নয়।
জাভাদবা

3

রূপান্তরকারী প্রতিনিধি আমাকে একসাথে কাজ করে উভয় ধারণাটি কল্পনা করতে সহায়তা করে:

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();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.