In primul rand, sa facem tipurile noastre de animale si pisici putin mai interesante adaugandu-le cateva proprietati:
clasa Animal
{
string ScientificName {get; a stabilit; }
} clasa Cat: Animal
{
string Breeze {get; a stabilit; }
}
In acest exemplu, stim din primele noastre zile de programare orientata pe obiecte ca un obiect de tip Cat poate inlocui un obiect de tip Animal deoarece Pisica este un subtip de Animal . Covarianta si contravarianta intra in joc de fiecare data cand incepem sa ne gandim la alte tipuri care „ depind de” tipuri precum Animal si Pisica . Sa vedem cateva exemple.
Array
Actiune <Animal> si Actiune <Cat>
Actiunea <T> este un tip generic din biblioteca de clase .NET, una care este destinata sa reprezinte o functie care asteapta un singur parametru de tip T si nu returneaza nimic (nul).
Cand tipuri precum Actiunea <T> sunt utilizate cu clase care au relatii de mostenire precum Animal si Pisica , ne confruntam cu situatii noi care ridica cateva intrebari interesante.
Array
De exemplu, stiind ca Pisica este un subtip de Animal , ar trebui sa fie posibila inlocuirea unei Actiuni care asteapta o Pisica cu alta care asteapta un Animal ? Si anume, este posibil sa utilizati Actiunea <Animal> intr-o expresie care asteapta Actiunea <Cat> ?
//
// Un exemplu de actiune <Animal> care
// tipareste Animal.ScientificName pe linia de comanda.
//
Actiune <Animal> animalAction =
(a) => Console.
Array
WriteLine (a.ScientificName); Action <Cat> catAction = animalAction; // Este valabil?
S-ar putea sa fiti tentati sa raspundeti: „In niciun caz! Cum putem inlocui o actiune care asteapta o pisica cu alta care asteapta un obiect de alt tip? ” Aceasta substitutie este de fapt posibila in acest caz, deoarece Pisica este un subtip de Animal . Daca nu intelegeti de ce, sa ne gandim la consecinte:
- catAction este o functie care asteapta o Cat
- Daca fragmentul de cod de mai sus este permis, invocarea catAction cu o Pisica va invoca animalAction trecandu-i acea Pisica , adica
Cat c = new Cat {ScientificName = “Felis catus”, Breed = “Asian”}; catAction (c); // Invoca: animalAction (c);
Este gresit sa apelezi animalAction cu un obiect Cat ? Cu siguranta nu.
- porno reel blizzaed.com
- pub porno iyfgmn.com
- porno petite bite rezseven.com
- porno gamine brianpark.com
- femmes nues porno www.bestaloevera.co.in
- teresa w porno 7ba.net
- porno cougard imageanywhere.com
- porno fornite www.jazzplaza.com
- cardi b porno vistara.in
- porno monstre stabilemoney.com
- film porno lesbien iaspire.com
- porno perfectgirl unrestrictedownloads.com
- porno jujufitcat bene.net
- porno beeg domainsrchr.com
- porno 90 games2boys.com
- porno entier dashwinstonsalem.com
- premier casting porno potatosnews.com
- 300 porno fenwaysports.com
- culotte porno 15minutos.net
- site porno coqnu woogamble.com
- magazine porno comindeed.com
- rihanna porno encorepacificmortgage.com
Este perfect valabil sa inlocuiti un animal cu o pisica . Aceasta este exact vechea noastra regula de baza despre programarea orientata pe obiecte, despre care am vorbit tot timpul. O consecinta directa a fi in masura sa inlocuiasca animale obiecte cu pisica obiecte este ca putem inlocui , de asemenea , o Actiune <Cat> cu o actiune <Animal> .
Este important sa observam ca substitutia inversa nu este valida. Iata un fragment de cod care explica de ce.
//
// Un exemplu de actiune <Cat> care
// tipareste Cat.Breed pe linia de comanda.
//
Action <Cat> catAction =
(c) => Console.WriteLine (c.Breed); Action <Animal> animalAction = catAction; // Este valabil? Nu! //
// Mai rau inca, daca fragmentul de mai sus ar fi valid, ar fi fost
// posibil sa invocam o Actiune <Cat> impotriva unui Animal!
//
Animal a = new Animal {ScientificName = “Canis lupus familiaris”}; animalAction (a); // Invoca efectiv catAction (a), dar obiectul a
// nu are o proprietate „Breed”!
Reprezentarea cheie este ca relatiile de mostenire intre tipuri au consecinte directe asupra schimbarii altor tipuri care depind de ele.
Func <Animal> si Func <Cat>
Func <T> este un alt tip .NET destinat sa reprezinte o functie care nu asteapta parametri si returneaza un obiect de tip T.
Iata o comparatie simpla intre Actiunea <T> si Func <T> :
- Ambele sunt tipuri .NET generice
- Ambele sunt utilizate pentru a se referi la functii
- Singura diferenta este ca Actiunea <T> reprezinta o functie care asteapta un obiect de tip T ca parametru, in timp ce Func <T> reprezinta o functie care returneaza un obiect de tip T.
//
// Un exemplu de Actiune <sir>
//
void Log (sir)
{
// Faceti ceva util cu s.
} //
// Un exemplu de Func <sir>
//
sir GetUserName ()
{
// returneaza un nume de utilizator.
} Actiune <sir> logAction = Jurnal;
Func <sir> getUserNameFunc = GetUserName;
Intrebarea pe care ar trebui sa ne-o punem acum este: putem inlocui un Func <Cat> cu un Func <Animal> asa cum am facut cu Actiunea <T> ?
//
// Un exemplu de Func <Animal> care returneaza un obiect Animal.
//
Func <Animal> animalFunc =
() => new Animal {ScientificName = “Canis lupus familiaris”}; Func <Cat> catFunc = animalFunc; // Este valabil?
Pentru a raspunde la aceasta intrebare, sa studiem consecintele:
- catFunc este o functie care returneaza un Cat
- animalFunc este o functie care returneaza un Animal
- Daca fragmentul de cod de mai sus este permis, catFunc va returna un Animal catre apelantul catFunc , care asteapta un Cat .
Cat c = catFunc (); // Apeleaza animalFunc () returnand un Animal.
Ar fi OK sa atribuiti un animal unei pisici ? Este exact ceea ce tutorii nostri de programare orientata pe obiecte ne-au avertizat: nu puteti atribui un parinte unui copil.
Spre deosebire de Actiunea <T> , nu este valid sa inlocuiti un Func <Cat> cu un Func <Animal> . Este posibila insa inlocuirea inversa? Putem inlocui Func <Animal> cu Func <Cat> ?
//
// Un exemplu de Func <Cat> care returneaza un obiect Cat.
//
Func <Cat> catFunc =
() => new Cat {ScientificName = “Felis catus”,
Breed = “Siaemese”}; Func <Animal> animalFunc = catFunc; // Este valabil?
Sa studiem consecintele:
- animalFunc este o functie care returneaza un Animal
- catFunc este o functie care returneaza un Cat
- Daca codul de mai sus este permis, animalFunc va invoca catFunc, returnand astfel o Pisica catre apelantul animalFunc , care asteapta un Animal . Dar asta este in regula, deoarece o Pisica este cu siguranta un Animal .
Pentru a rezuma, o consecinta directa a relatiei de mostenire dintre Pisica si Animal este ca putem inlocui un Func <Animal> cu un Func <Cat> .








