Compartilhar via


Usando variação em interfaces para coleções genéricas (C# e Visual Basic)

Uma interface covariant permite que os seus métodos retornar mais tipos derivados além daqueles especificados da interface. Uma interface contravariant permite que os seus métodos aceitar parâmetros de menos tipos derivados além daqueles especificados na interface.

No.NET Framework 4, várias interfaces existentes se tornam covariant e contravariant. Eles incluem IEnumerable e IComparable. Isso lhe permite reutilizar os métodos que operam com coleções genéricas dos tipos base para coleções de tipos derivados.

Para obter uma lista de interfaces variant na.NET Framework, consulte Variação em interfaces genéricas (C# e Visual Basic).

Convertendo coleções genéricas

O exemplo a seguir ilustra os benefícios do suporte a covariância na IEnumerable interface. O PrintFullName método aceita uma coleção da IEnumerable<Person> tipo (IEnumerable(Of Person) em Visual Basic) como um parâmetro. No entanto, você pode reutilizá-la para uma coleção da IEnumerable<Employee> tipo (IEnumerable(Of Person) em Visual Basic) porque Employee herda Person.

' Simple hierarchy of classes. 
Public Class Person
    Public Property FirstName As String 
    Public Property LastName As String 
End Class 

Public Class Employee
    Inherits Person
End Class 

' The method has a parameter of the IEnumerable(Of Person) type. 
Public Sub PrintFullName(ByVal persons As IEnumerable(Of Person))
    For Each person As Person In persons
        Console.WriteLine(
            "Name: " & person.FirstName & " " & person.LastName)
    Next 
End Sub 

Sub Main()
    Dim employees As IEnumerable(Of Employee) = New List(Of Employee)

    ' You can pass IEnumerable(Of Employee),  
    ' although the method expects IEnumerable(Of Person).

    PrintFullName(employees)

End Sub
// Simple hierarchy of classes. 
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Employee : Person { }

class Program
{
    // The method has a parameter of the IEnumerable<Person> type. 
    public static void PrintFullName(IEnumerable<Person> persons)
    {
        foreach (Person person in persons)
        {
            Console.WriteLine("Name: {0} {1}",
            person.FirstName, person.LastName);
        }
    }

    public static void Test()
    {
        IEnumerable<Employee> employees = new List<Employee>();

        // You can pass IEnumerable<Employee>,  
        // although the method expects IEnumerable<Person>.

        PrintFullName(employees);

    }
}

Comparando coleções genéricas

O exemplo a seguir ilustra os benefícios do suporte/contravariância na IComparer interface. O PersonComparer classe implementa o IComparer<Person> interface (IComparer(Of Person) em Visual Basic). No entanto, você pode reutilizar essa classe para comparar uma seqüência de objetos da Employee tipo porque Employee herda Person.

' Simple hierarhcy of classes. 
Public Class Person
    Public Property FirstName As String 
    Public Property LastName As String 
End Class 

Public Class Employee
    Inherits Person
End Class 
' The custom comparer for the Person type 
' with standard implementations of Equals() 
' and GetHashCode() methods. 
Class PersonComparer
    Implements IEqualityComparer(Of Person)

    Public Function Equals1(
        ByVal x As Person,
        ByVal y As Person) As Boolean _
        Implements IEqualityComparer(Of Person).Equals

        If x Is y Then Return True 
        If x Is Nothing OrElse y Is Nothing Then Return False 
        Return (x.FirstName = y.FirstName) AndAlso
            (x.LastName = y.LastName)
    End Function 
    Public Function GetHashCode1(
        ByVal person As Person) As Integer _
        Implements IEqualityComparer(Of Person).GetHashCode

        If person Is Nothing Then Return 0
        Dim hashFirstName =
            If(person.FirstName Is Nothing,
            0, person.FirstName.GetHashCode())
        Dim hashLastName = person.LastName.GetHashCode()
        Return hashFirstName Xor hashLastName
    End Function 
End Class 

Sub Main()
    Dim employees = New List(Of Employee) From {
        New Employee With {.FirstName = "Michael", .LastName = "Alexander"},
        New Employee With {.FirstName = "Jeff", .LastName = "Price"}
    }

    ' You can pass PersonComparer,  
    ' which implements IEqualityComparer(Of Person), 
    ' although the method expects IEqualityComparer(Of Employee) 

    Dim noduplicates As IEnumerable(Of Employee) = employees.Distinct(New PersonComparer())

    For Each employee In noduplicates
        Console.WriteLine(employee.FirstName & " " & employee.LastName)
    Next 
End Sub
// Simple hierarchy of classes. 
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Employee : Person { }

// The custom comparer for the Person type 
// with standard implementations of Equals() 
// and GetHashCode() methods. 
class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {            
        if (Object.ReferenceEquals(x, y)) return true;
        if (Object.ReferenceEquals(x, null) ||
            Object.ReferenceEquals(y, null))
            return false;            
        return x.FirstName == y.FirstName && x.LastName == y.LastName;
    }
    public int GetHashCode(Person person)
    {
        if (Object.ReferenceEquals(person, null)) return 0;
        int hashFirstName = person.FirstName == null
            ? 0 : person.FirstName.GetHashCode();
        int hashLastName = person.LastName.GetHashCode();
        return hashFirstName ^ hashLastName;
    }
}

class Program
{

    public static void Test()
    {
        List<Employee> employees = new List<Employee> {
               new Employee() {FirstName = "Michael", LastName = "Alexander"},
               new Employee() {FirstName = "Jeff", LastName = "Price"}
            };

        // You can pass PersonComparer,  
        // which implements IEqualityComparer<Person>, 
        // although the method expects IEqualityComparer<Employee>.

        IEnumerable<Employee> noduplicates =
            employees.Distinct<Employee>(new PersonComparer());

        foreach (var employee in noduplicates)
            Console.WriteLine(employee.FirstName + " " + employee.LastName);
    }
}

Consulte também

Conceitos

Variação em interfaces genéricas (C# e Visual Basic)