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

এবং কোডে:
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