Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ezek a példák bemutatják, hogyan használhatja a kovarianciát és a kontravarianciát az Func és Action általános delegátumokban a metódusok újrafelhasználásának engedélyezéséhez és a kód rugalmasságának biztosításához.
A kovarianciáról és a kontravarianciáról további információt a Delegáltak varianciája (C#) című témakörben talál.
Delegáltak használata kovariáns típusparaméterekkel
Az alábbi példa a kovariáns támogatás előnyeit mutatja be az általános Func delegátumokban. A FindByTitle metódus a típus paraméterét String veszi fel, és visszaadja a Employee típus egy objektumát. Ezt a metódust azonban hozzárendelheti a Func<String, Person> meghatalmazotthoz, mert Employee örökli Person.
// Simple hierarchy of classes.
public class Person { }
public class Employee : Person { }
class Program
{
static Employee FindByTitle(String title)
{
// This is a stub for a method that returns
// an employee that has the specified title.
return new Employee();
}
static void Test()
{
// Create an instance of the delegate without using variance.
Func<String, Employee> findEmployee = FindByTitle;
// The delegate expects a method to return Person,
// but you can assign it a method that returns Employee.
Func<String, Person> findPerson = FindByTitle;
// You can also assign a delegate
// that returns a more derived type
// to a delegate that returns a less derived type.
findPerson = findEmployee;
}
}
Meghatalmazottak használata contravariáns típusú paraméterekkel
Az alábbi példa a contravariance támogatás előnyeit mutatja be az Action általános delegáltakban. A AddToContacts metódus egy ilyen típusú paramétert Person használ. Ezt a metódust azonban hozzárendelheti a Action<Employee> meghatalmazotthoz, mert Employee örökli Person.
public class Person { }
public class Employee : Person { }
class Program
{
static void AddToContacts(Person person)
{
// This method adds a Person object
// to a contact list.
}
static void Test()
{
// Create an instance of the delegate without using variance.
Action<Person> addPersonToContacts = AddToContacts;
// The Action delegate expects
// a method that has an Employee parameter,
// but you can assign it a method that has a Person parameter
// because Employee derives from Person.
Action<Employee> addEmployeeToContacts = AddToContacts;
// You can also assign a delegate
// that accepts a less derived parameter to a delegate
// that accepts a more derived parameter.
addEmployeeToContacts = addPersonToContacts;
}
}
Contravariance és névtelen függvények
Névtelen függvények (lambdakifejezések) használatakor előfordulhat, hogy ellentétes viselkedést tapasztal a contravariance használatával kapcsolatban. Vegye figyelembe a következő példát:
public class Person
{
public virtual void ReadContact() { /*...*/ }
}
public class Employee : Person
{
public override void ReadContact() { /*...*/ }
}
class Program
{
private static void Main()
{
var personReadContact = (Person p) => p.ReadContact();
// This works - contravariance allows assignment.
Action<Employee> employeeReadContact = personReadContact;
// This causes a compile error: CS1661.
// Action<Employee> employeeReadContact2 = (Person p) => p.ReadContact();
}
}
Ez a viselkedés ellentmondásosnak tűnik: ha a contravariance lehetővé teszi egy olyan delegált hozzárendelését, amely elfogadja az alaptípust (Person) egy származtatott típust váró delegált változóhoz (Employee), miért nem sikerül a lambda kifejezés közvetlen hozzárendelése?
A fő különbség a típusbeli következtetés. Az első esetben a lambda kifejezés először egy típussal varrendelkező változóhoz van hozzárendelve, ami azt eredményezi, hogy a fordító a lambda típusát a következőképpen Action<Person>adhatja meg. A következő feladat sikeres lesz Action<Employee> , mert a meghatalmazottakra vonatkozó szabályt megsértik.
A második esetben a fordító nem tud közvetlenül arra következtetni, hogy a lambda kifejezésnek (Person p) => p.ReadContact() típusnak Action<Person> kell lennie, amikor hozzá van rendelve Action<Employee>. A névtelen függvények típuskövető szabályai nem alkalmazzák automatikusan a kontratravarianciát a kezdeti típusmeghatározás során.
Áthidaló megoldások
A közvetlen hozzárendelési munka elvégzéséhez használhat explicit öntést:
// Explicit cast to the desired delegate type.
Action<Employee> employeeReadContact = (Action<Person>)((Person p) => p.ReadContact());
// Or specify the lambda parameter type that matches the target delegate.
Action<Employee> employeeReadContact2 = (Employee e) => e.ReadContact();
Ez a viselkedés szemlélteti a delegált ellentravariancia (amely a típusok létrehozása után működik) és a lambda kifejezéstípus-következtetés (amely a fordítás során következik be) közötti különbséget.