ПредишенСледващото

настроен 24 април '16 в 18:36

Не е ясно как да се конструира covariant и contravariant. Примерът показва, че делегата може да получи референция към две методи с различни входни и изходни параметри. Тук е промяната в ChangeIt ковариация = IncrB; и Contravariant ChangeIt промяна = IncrA;? Като цяло, няма ясна дефиниция на covariant и contravariant, те са твърде объркваща. - NaughtyBrain 24 апр '16 в 19:20

За да започнете, нека да погледнем какво е отклонението.

Да предположим, че имаме два класа, кола и BMW. Ясно е, че BMW има разделение на кола. всеки BEHA една машина.

Обикновено това казват: "всеки път, когато използвате колата. Можете да използвате и БМВ-то. » Това всъщност е почти вярно, но не съвсем.

Пример: ако имате списък с машини, не можете да го използвате вместо списък на BMW. Защо? И ето защо. Нека имате Списък. и да го използвате като списък с машини. След това, просто списък с машини. е възможно да се добави и Запорожец Lanos, нали? Това е мястото, където започват проблемите. Ако е писано във вашия код:

Ако имахме списък на достъпна само за четене. проблемите просто не е бил:

Така че това, което правим? Въпреки факта, че BMW - автомобил, BMW списък не е задължително списък с машини. И тук е списък на BMW, е достъпна само за четене, след като в списъка на машини.

Сега обратно към дисперсията. Ние говорим за ковариацията в най-общ смисъл, ако нещо се променя по същия начин. В случай на класове на наследството, че можем да използваме вместо кола BMW. и просто, колкото можем, вместо IEnumerable използвате IEnumerable .

Добре, че е дълго въведение, а сега обратно към темата: ковариация делегати. Да предположим, че имаме делегат, в зависимост от типа автомобил. Промени в своето определение в кола BMW. дали е възможно да се използва нов делегат да замени стария?

Да помислим логично. Ако имаме делегат:

(Car Приема вход и произвежда друг случай на кола.), След това дали е възможно вместо да замени функцията описваща делегати този тип:

Не, разбира се, тъй като делегат може да получите на входа на всяка функция, както и нашата функция иска само да BMW. Така че няма ковариация: тази функция не може да се използва там, където искате делегата.

Но ако нашият вариант Тип данни (тоест, кола) е само в позицията на типа на връщане:

след това на негово място, можете да използвате функцията по следния начин:

(Ако се обърне всеки автомобил, BMW също е хубаво).

Това е ковариацията на делегатите, където от вас в кода изисква да делегира, можете да дадете вместо covariant делегат.

Примерен код, че той използва:

Contravariance работи по друг начин: там можете да използвате делегат работа с вида на основата, където се очаква да се делегира на производния клас. Това работи за аргументи на функция:

Тя работи по същите причини като ковариацията: Ако тестера се вписва всеки тип машина, тя може да работи с BMW, също.

Всеки от родово параметри тип делегат или интерфейс трябва да се маркира като covariant и contravariant. Това не води до някакви непредвидени последствия, но ви позволява да използвате вашите делегати в повече сценарии и ще ви даде възможност да се направи отливка на променливата обща делегата от същия тип, с различен параметър делегат тип.

Тип параметри могат да бъдат:

  • Инвариантна. параметър тип не може да бъде променено.
  • Contravariant. параметър тип могат да бъдат превърнати от класа на
    класове, получени от него. В C #, а contravariant вид
    определена ключова дума инча параметър Тип contravariant
    Тя може да се появи само в позицията за въвеждане, като например
    метод аргументи.
  • Ковариация. тип аргумент може да бъде изчислена от класа на един от своите основни класове. В C #, а covariant вид, обозначен с ключова дума навън. Covariant родово тип параметър може да се появи само в позицията на изхода, например, като стойността на връщане на метода.

Да предположим, че следният тип делегат:

Тук, параметър T-тип маркирана дума инча което го прави contravariant и параметър тип дума TResult маркирана. вземане на ковариация. Нека съобщиха от следните променливи:

Това може да доведе до вид MyDelegate с други параметри, типове:

Това предполага, че fn1 се отнася до функция, която се обект и се връща ArgumentException. Частично fn2 се опитва да се отнася до метод, който отнема String и връща изключение. Тъй като може да премине метод String, което изисква тип обект (от тип String е получен от обекта) и резултатите от метода връщат ArgumentException. може да се тълкува като Изключение (тип ArgumentException е получен от Изключение), кодът представени тук се изготвя, и по време на безопасност тип компилация ще се поддържа.

Забележка: дисперсията е валидно само ако компилаторът е в състояние да установи способността да конвертирате между видовете връзки. С други думи, по-значителни отклонения не се прилага за видове нужда опаковката на (бокс).

Свързани статии

Подкрепете проекта - споделете линка, благодаря!