Share via


Colecciones (C# y Visual Basic)

En muchas aplicaciones se desea poder crear y administrar grupos de objetos relacionados.Existen dos formas de agrupar objetos: mediante la creación de matrices de objetos y mediante la creación de colecciones de objetos.

Las matrices son muy útiles para crear y trabajar con un número fijo de objetos fuertemente tipados.Para obtener información sobre matrices, vea Matrices en Visual Basic or Matrices (Guía de programación de C#).

Las colecciones proporcionan un método más flexible para trabajar con grupos de objetos.A diferencia de las matrices, el grupo de objetos con el que trabaja puede aumentar y reducirse dinámicamente a medida que cambian las necesidades de la aplicación.Para algunas colecciones, puede asignar una clave a cualquier objeto que incluya en la colección para que pueda recuperar rápidamente el objeto con la clave asignada.

Una colección es una clase, de modo que antes de poder agregar elementos a una nueva colección, debe declararla.

Si su colección se limita a elementos de sólo un tipo de datos, puede utilizar una de las clases en el espacio de nombres System.Collections.Generic.Una colección genérica cumple la seguridad de tipos para que ningún otro tipo de datos se pueda agregar a ella.Cuando recupera un elemento de una colección genérica, no tiene que determinar su tipo de datos ni convertirlo.

[!NOTA]

Para los ejemplos de este tema, incluya expresiones Imports (Visual Basic) o directivas using (C#) para los espacios de nombres System.Collections.Generic y System.Linq .

En este tema

  • Usando una colección Simple

  • Clases de colecciones

    • Clases del espacio de nombres System.Collections.Generic

    • Clases del espacio de nombres System.Collections.Concurrent

    • Clases System.Collections

    • Clase de colección de Visual Basic

  • Implementar una colección de pares clave/valor

  • Usar LINQ para obtener acceso a una colección

  • Ordenar una colección

  • Definir una colección personalizada

  • Iteradores

Usando una colección Simple

Los ejemplos de esta sección usan la clase genérica List<T>, que permite trabajar con una lista de objetos fuertemente tipados.

En el ejemplo siguiente se crea una lista de cadenas y a continuación se itera a través de las cadenas mediante una expresión For Each… Next (Visual Basic) o foreach (C#).

' Create a list of strings.
Dim salmons As New List(Of String)
salmons.Add("chinook")
salmons.Add("coho")
salmons.Add("pink")
salmons.Add("sockeye")

' Iterate through the list.
For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye
// Create a list of strings.
var salmons = new List<string>();
salmons.Add("chinook");
salmons.Add("coho");
salmons.Add("pink");
salmons.Add("sockeye");

// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

Si el contenido de una colección se conoce de antemano, puede utilizar un inicializador de colección para inicializar la colección.Para obtener más información, vea Inicializadores de colección (Visual Basic) o Inicializadores de objeto y de colección (Guía de programación de C#).

El ejemplo siguiente es igual al ejemplo anterior, excepto que se utiliza un inicializador de colección para agregar elementos a la colección.

' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye
// Create a list of strings by using a
// collection initializer.
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

Puede utilizar una expresión For… Next (Visual Basic) o for (C#) en lugar de una instrucción For Each para recorrer en iteración una colección.Esto se consigue al obtener acceso a los elementos de la colección mediante el índice de posición.El índice de los elementos comienza en 0 y finaliza en el número de elementos menos 1.

El ejemplo siguiente recorre en iteración los elementos de una colección utilizando For…Next en lugar de For Each.

Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

For index = 0 To salmons.Count - 1
    Console.Write(salmons(index) & " ")
Next
'Output: chinook coho pink sockeye
// Create a list of strings by using a
// collection initializer.
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

for (var index = 0; index < salmons.Count; index++)
{
    Console.Write(salmons[index] + " ");
}
// Output: chinook coho pink sockeye

El ejemplo siguiente elimina un elemento de la colección especificando el objeto que se va a eliminar.

' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

' Remove an element in the list by specifying
' the object.
salmons.Remove("coho")

For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook pink sockeye
// Create a list of strings by using a
// collection initializer.
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Remove an element from the list by specifying
// the object.
salmons.Remove("coho");

// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook pink sockeye

El ejemplo siguiente elimina elementos de una lista genérica.En lugar de una expresión For Each, se utiliza una expresión For… Next (Visual Basic) o for (C#) que itera en orden descendente.Esto ese debe a que el método RemoveAt hace que los elementos que hay después del elemento eliminado tengan un valor de índice más bajo.

Dim numbers As New List(Of Integer) From
    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

' Remove odd numbers.
For index As Integer = numbers.Count - 1 To 0 Step -1
    If numbers(index) Mod 2 = 1 Then
        ' Remove the element by specifying
        ' the zero-based index in the list.
        numbers.RemoveAt(index)
    End If
Next

' Iterate through the list.
' A lambda expression is placed in the ForEach method
' of the List(T) object.
numbers.ForEach(
    Sub(number) Console.Write(number & " "))
' Output: 0 2 4 6 8
var numbers = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// Remove odd numbers.
for (var index = numbers.Count - 1; index >= 0; index--)
{
    if (numbers[index] % 2 == 1)
    {
        // Remove the element by specifying
        // the zero-based index in the list.
        numbers.RemoveAt(index);
    }
}

// Iterate through the list.
// A lambda expression is placed in the ForEach method
// of the List(T) object.
numbers.ForEach(
    number => Console.Write(number + " "));
// Output: 0 2 4 6 8

Para el tipo de elementos en List<T>, también puede definir su propia clase.En el ejemplo siguiente, la clase Galaxy utilizada por List<T> se define en el código.

Private Sub IterateThroughList()
    Dim theGalaxies As New List(Of Galaxy) From
        {
            New Galaxy With {.Name = "Tadpole", .MegaLightYears = 400},
            New Galaxy With {.Name = "Pinwheel", .MegaLightYears = 25},
            New Galaxy With {.Name = "Milky Way", .MegaLightYears = 0},
            New Galaxy With {.Name = "Andromeda", .MegaLightYears = 3}
        }

    For Each theGalaxy In theGalaxies
        With theGalaxy
            Console.WriteLine(.Name & "  " & .MegaLightYears)
        End With
    Next

    ' Output:
    '  Tadpole  400
    '  Pinwheel  25
    '  Milky Way  0
    '  Andromeda  3
End Sub

Public Class Galaxy
    Public Property Name As String
    Public Property MegaLightYears As Integer
End Class
private void IterateThroughList()
{
    var theGalaxies = new List<Galaxy>
        {
            new Galaxy() { Name="Tadpole", MegaLightYears=400},
            new Galaxy() { Name="Pinwheel", MegaLightYears=25},
            new Galaxy() { Name="Milky Way", MegaLightYears=0},
            new Galaxy() { Name="Andromeda", MegaLightYears=3}
        };

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears);
    }

    // Output:
    //  Tadpole  400
    //  Pinwheel  25
    //  Milky Way  0
    //  Andromeda  3
}

public class Galaxy
{
    public string Name { get; set; }
    public int MegaLightYears { get; set; }
}

Clases de colecciones

Varias colecciones comunes son proporcionadas por el .NET Framework.Cada tipo de colección está diseñado para un propósito concreto.

Los siguientes grupos de clases de colección están descritos en esta sección:

  • Clases System.Collections.Generic.

  • Clases System.Collections.Concurrent.

  • Clases System.Collections.

  • Clase Collection de Visual Basic

ybcx56wz.collapse_all(es-es,VS.110).gifClases del espacio de nombres System.Collections.Generic

Se puede crear una colección genérica utilizando una de las clases en el espacio de nombres System.Collections.Generic.Una colección genérica es útil cuando todos los elementos de la colección tienen el mismo tipo de datos.Una colección genérica cumple el tipado fuerte al permitir agregar sólo el tipo de datos deseado.

La tabla siguiente muestra algunas de las clases utilizadas con frecuencia del espacio de nombres System.Collections.Generic :

Clase

Descripción

[ T:System.Collections.Generic.Dictionary`2 ]

Representa una colección de pares de clave y valor que se organizan por claves.

[ T:System.Collections.Generic.List`1 ]

Representa una lista de objetos que pueden ser obtenidos mediante un índice.Proporciona métodos para buscar, ordenar y modificar listas.

[ T:System.Collections.Generic.Queue`1 ]

Representa una colección de objetos con el orden primero en entrar, primero en salir (FIFO).

[ T:System.Collections.Generic.SortedList`2 ]

Representa una colección de pares de clave y valor que se ordenan por claves según la implementación de la interfaz IComparer<T> asociada.

[ T:System.Collections.Generic.Stack`1 ]

Representa una colección de objetos con el orden último en entrar, primero en salir (LIFO).

Para obtener más información, vea Tipos de colección utilizados normalmente, Seleccionar una clase de colección y System.Collections.Generic.

ybcx56wz.collapse_all(es-es,VS.110).gifClases del espacio de nombres System.Collections.Concurrent

En el .NET Framework 4, las colecciones en el espacio de nombres System.Collections.Concurrent proporcionan operaciones eficaces y seguras para subprocesos con el fin de obtener acceso a los elementos de colección desde varios subprocesos.

Las clases del espacio de nombres System.Collections.Concurrent deben utilizarse en lugar de sus equivalentes en los espacios de nombres System.Collections.Generic y System.Collections cuando varios subprocesos tienen acceso a la colección simultáneamente.Para obtener más información, vea Colecciones seguras para subprocesos y System.Collections.Concurrent.

Algunas clases incluidas en el espacio de nombres System.Collections.Concurrent son BlockingCollection<T>, ConcurrentDictionary<TKey, TValue>, ConcurrentQueue<T>, y ConcurrentStack<T>.

ybcx56wz.collapse_all(es-es,VS.110).gifClases System.Collections

Las clases del espacio de nombres System.Collections no almacenan los elementos como objetos de un tipo específico, sino como objetos de tipo Object.

Siempre que sea posible, se deberían utilizar las colecciones genéricas del espacio de nombres System.Collections.Generic o del espacio de nombres System.Collections.Concurrent en lugar de los tipos legados en el espacio de nombres System.Collections .

La tabla siguiente muestra algunas de las clases utilizadas con frecuencia en el espacio de nombres System.Collections :

Clase

Descripción

[ T:System.Collections.ArrayList ]

Representa una matriz de objetos cuyo tamaño aumenta dinámicamente según sea necesario.

[ T:System.Collections.Hashtable ]

Representa una colección de pares de clave y valor que se organizan por código hash de la clave.

[ T:System.Collections.Queue ]

Representa una colección de objetos con el orden primero en entrar, primero en salir (FIFO).

[ T:System.Collections.Stack ]

Representa una colección de objetos con el orden último en entrar, primero en salir (LIFO).

El espacio de nombres System.Collections.Specialized proporciona clases de colección especializadas y fuertemente tipadas, como colecciones de solo cadena y diccionarios híbridos y de lista vinculada.

ybcx56wz.collapse_all(es-es,VS.110).gifClase de colección de Visual Basic

Puede utilizar la clase de Visual Basic Collection para obtener acceso a un elemento de colección mediante un índice numérico o una clave de tipo String .Puede agregar elementos a un objeto de colección ya sea especificando una clave o no especificándola.Si agrega un elemento sin una clave, debe utilizar su índice numérico para tener acceso a él.

La clase Collection de Visual Basic almacena todos sus elementos como tipo Object, por lo que es posible agregar un elemento de cualquier tipo de datos.No hay ningún método de protección contra los tipos de datos inadecuados que se agreguen.

Cuando se utiliza la clase de Visual Basic Collection, el índice del primer elemento tiene un valor de 1.Esto difiere de las clases de colección de .NET Framework, para las cuales el índice inicial es 0.

Siempre que sea posible, se deben utilizar las colecciones genéricas de los espacio de nombres System.Collections.Generic o System.Collections.Concurrent en lugar de la clase de Visual Basic Collection.

Para obtener más información, vea Collection.

Implementar una colección de pares clave/valor

La colección genérica Dictionary<TKey, TValue> permite obtener acceso a los elementos en una colección utilizando la clave de cada elemento.Cada elemento que se agrega al diccionario está compuesto de un valor y su clave asociada.Recuperar un valor utilizando su clave es muy rápido debido a que la clase Dictionary se implementa como una tabla hash.

El ejemplo siguiente crea una colección Dictionary y la recorre en iteración a través del diccionario utilizando una expresión For Each.

Private Sub IterateThroughDictionary()
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    For Each kvp As KeyValuePair(Of String, Element) In elements
        Dim theElement As Element = kvp.Value

        Console.WriteLine("key: " & kvp.Key)
        With theElement
            Console.WriteLine("values: " & .Symbol & " " &
                .Name & " " & .AtomicNumber)
        End With
    Next
End Sub

Private Function BuildDictionary() As Dictionary(Of String, Element)
    Dim elements As New Dictionary(Of String, Element)

    AddToDictionary(elements, "K", "Potassium", 19)
    AddToDictionary(elements, "Ca", "Calcium", 20)
    AddToDictionary(elements, "Sc", "Scandium", 21)
    AddToDictionary(elements, "Ti", "Titanium", 22)

    Return elements
End Function

Private Sub AddToDictionary(ByVal elements As Dictionary(Of String, Element),
ByVal symbol As String, ByVal name As String, ByVal atomicNumber As Integer)
    Dim theElement As New Element

    theElement.Symbol = symbol
    theElement.Name = name
    theElement.AtomicNumber = atomicNumber

    elements.Add(Key:=theElement.Symbol, value:=theElement)
End Sub

Public Class Element
    Public Property Symbol As String
    Public Property Name As String
    Public Property AtomicNumber As Integer
End Class
private void IterateThruDictionary()
{
    Dictionary<string, Element> elements = BuildDictionary();

    foreach (KeyValuePair<string, Element> kvp in elements)
    {
        Element theElement = kvp.Value;

        Console.WriteLine("key: " + kvp.Key);
        Console.WriteLine("values: " + theElement.Symbol + " " +
            theElement.Name + " " + theElement.AtomicNumber);
    }
}

private Dictionary<string, Element> BuildDictionary()
{
    var elements = new Dictionary<string, Element>();

    AddToDictionary(elements, "K", "Potassium", 19);
    AddToDictionary(elements, "Ca", "Calcium", 20);
    AddToDictionary(elements, "Sc", "Scandium", 21);
    AddToDictionary(elements, "Ti", "Titanium", 22);

    return elements;
}

private void AddToDictionary(Dictionary<string, Element> elements,
    string symbol, string name, int atomicNumber)
{
    Element theElement = new Element();

    theElement.Symbol = symbol;
    theElement.Name = name;
    theElement.AtomicNumber = atomicNumber;

    elements.Add(key: theElement.Symbol, value: theElement);
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

En cambio, para utilizar un inicializador de colección para compilar la colección de Dictionary, puede reemplazar los métodos BuildDictionary y AddToDictionary con el siguiente método.

Private Function BuildDictionary2() As Dictionary(Of String, Element)
    Return New Dictionary(Of String, Element) From
        {
            {"K", New Element With
                {.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
            {"Ca", New Element With
                {.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
            {"Sc", New Element With
                {.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
            {"Ti", New Element With
                {.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
        }
End Function
private Dictionary<string, Element> BuildDictionary2()
{
    return new Dictionary<string, Element>
    {
        {"K",
            new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
        {"Ca",
            new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        {"Sc",
            new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        {"Ti",
            new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };
}

El ejemplo siguiente usa el método ContainsKey y la propiedad Item de Dictionary para buscar rápidamente un elemento por clave.La propiedad Item permite obtener acceso a un elemento de la colección elements usando el código elements(symbol) en Visual Basic, o elements[symbol] en C#.

Private Sub FindInDictionary(ByVal symbol As String)
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    If elements.ContainsKey(symbol) = False Then
        Console.WriteLine(symbol & " not found")
    Else
        Dim theElement = elements(symbol)
        Console.WriteLine("found: " & theElement.Name)
    End If
End Sub
private void FindInDictionary(string symbol)
{
    Dictionary<string, Element> elements = BuildDictionary();

    if (elements.ContainsKey(symbol) == false)
    {
        Console.WriteLine(symbol + " not found");
    }
    else
    {
        Element theElement = elements[symbol];
        Console.WriteLine("found: " + theElement.Name);
    }
}

El ejemplo siguiente utiliza en su lugar el método TryGetValue para encontrar rápidamente un elemento por clave.

Private Sub FindInDictionary2(ByVal symbol As String)
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    Dim theElement As Element = Nothing
    If elements.TryGetValue(symbol, theElement) = False Then
        Console.WriteLine(symbol & " not found")
    Else
        Console.WriteLine("found: " & theElement.Name)
    End If
End Sub
private void FindInDictionary2(string symbol)
{
    Dictionary<string, Element> elements = BuildDictionary();

    Element theElement = null;
    if (elements.TryGetValue(symbol, out theElement) == false)
        Console.WriteLine(symbol + " not found");
    else
        Console.WriteLine("found: " + theElement.Name);
}

Usar LINQ para obtener acceso a una colección

LINQ (Consultas de lenguaje integrado) se puede utilizar para obtener acceso a las colecciones.Las consultas LINQ proporcionan capacidades de filtrado, ordenación y agrupación.Para obtener más información, vea Introducción a LINQ en Visual Basic o Introducción a LINQ en C#.

El ejemplo siguiente ejecuta una consulta LINQ contra una List genérica.La consulta LINQ devuelve otra colección que contiene los resultados.

Private Sub ShowLINQ()
    Dim elements As List(Of Element) = BuildList()

    ' LINQ Query.
    Dim subset = From theElement In elements
                  Where theElement.AtomicNumber < 22
                  Order By theElement.Name

    For Each theElement In subset
        Console.WriteLine(theElement.Name & " " & theElement.AtomicNumber)
    Next

    ' Output:
    '  Calcium 20
    '  Potassium 19
    '  Scandium 21
End Sub

Private Function BuildList() As List(Of Element)
    Return New List(Of Element) From
        {
            {New Element With
                {.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
            {New Element With
                {.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
            {New Element With
                {.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
            {New Element With
                {.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
        }
End Function

Public Class Element
    Public Property Symbol As String
    Public Property Name As String
    Public Property AtomicNumber As Integer
End Class
private void ShowLINQ()
{
    List<Element> elements = BuildList();

    // LINQ Query.
    var subset = from theElement in elements
                 where theElement.AtomicNumber < 22
                 orderby theElement.Name
                 select theElement;

    foreach (Element theElement in subset)
    {
        Console.WriteLine(theElement.Name + " " + theElement.AtomicNumber);
    }

    // Output:
    //  Calcium 20
    //  Potassium 19
    //  Scandium 21
}

private List<Element> BuildList()
{
    return new List<Element>
    {
        { new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
        { new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        { new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        { new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

Ordenar una colección

El ejemplo siguiente muestra un procedimiento para ordenar una colección.El ejemplo ordena instancias de la clase Car almacenadas en una List<T>.La clase Car implementa la interfaz IComparable<T>, que requiere que el método CompareTo se implemente.

Cada llamada al método CompareTo hace una única comparación que se utiliza para ordenar.El código escrito por el usuario en el método CompareTo devuelve un valor para cada comparación del objeto actual con otro objeto.El valor devuelto es menor que cero si el objeto actual es menor que otro objeto, mayor que cero si el objeto actual es mayor que otro objeto y cero si son iguales.Esto permite definir en el código los criterios para la evaluación mayor que, menor que, e igual que.

En el método ListCars, la expresión cars.Sort() ordena la lista.Esta llamada al método Sort de List<T> hace que el método CompareTo sea llamado automáticamente para los objetos de clase Car en List.

Public Sub ListCars()

    ' Create some new cars.
    Dim cars As New List(Of Car) From
    {
        New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
        New Car With {.Name = "car2", .Color = "red", .Speed = 50},
        New Car With {.Name = "car3", .Color = "green", .Speed = 10},
        New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
        New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
        New Car With {.Name = "car6", .Color = "red", .Speed = 60},
        New Car With {.Name = "car7", .Color = "green", .Speed = 50}
    }

    ' Sort the cars by color alphabetically, and then by speed
    ' in descending order.
    cars.Sort()

    ' View all of the cars.
    For Each thisCar As Car In cars
        Console.Write(thisCar.Color.PadRight(5) & " ")
        Console.Write(thisCar.Speed.ToString & " ")
        Console.Write(thisCar.Name)
        Console.WriteLine()
    Next

    ' Output:
    '  blue  50 car4
    '  blue  30 car5
    '  blue  20 car1
    '  green 50 car7
    '  green 10 car3
    '  red   60 car6
    '  red   50 car2
End Sub

Public Class Car
    Implements IComparable(Of Car)

    Public Property Name As String
    Public Property Speed As Integer
    Public Property Color As String

    Public Function CompareTo(ByVal other As Car) As Integer _
        Implements System.IComparable(Of Car).CompareTo
        ' A call to this method makes a single comparison that is
        ' used for sorting.

        ' Determine the relative order of the objects being compared.
        ' Sort by color alphabetically, and then by speed in
        ' descending order.

        ' Compare the colors.
        Dim compare As Integer
        compare = String.Compare(Me.Color, other.Color, True)

        ' If the colors are the same, compare the speeds.
        If compare = 0 Then
            compare = Me.Speed.CompareTo(other.Speed)

            ' Use descending order for speed.
            compare = -compare
        End If

        Return compare
    End Function
End Class
private void ListCars()
{
    var cars = new List<Car>
    {
        { new Car() { Name = "car1", Color = "blue", Speed = 20}},
        { new Car() { Name = "car2", Color = "red", Speed = 50}},
        { new Car() { Name = "car3", Color = "green", Speed = 10}},
        { new Car() { Name = "car4", Color = "blue", Speed = 50}},
        { new Car() { Name = "car5", Color = "blue", Speed = 30}},
        { new Car() { Name = "car6", Color = "red", Speed = 60}},
        { new Car() { Name = "car7", Color = "green", Speed = 50}}
    };

    // Sort the cars by color alphabetically, and then by speed
    // in descending order.
    cars.Sort();

    // View all of the cars.
    foreach (Car thisCar in cars)
    {
        Console.Write(thisCar.Color.PadRight(5) + " ");
        Console.Write(thisCar.Speed.ToString() + " ");
        Console.Write(thisCar.Name);
        Console.WriteLine();
    }

    // Output:
    //  blue  50 car4
    //  blue  30 car5
    //  blue  20 car1
    //  green 50 car7
    //  green 10 car3
    //  red   60 car6
    //  red   50 car2
}

public class Car : IComparable<Car>
{
    public string Name { get; set; }
    public int Speed { get; set; }
    public string Color { get; set; }

    public int CompareTo(Car other)
    {
        // A call to this method makes a single comparison that is
        // used for sorting.

        // Determine the relative order of the objects being compared.
        // Sort by color alphabetically, and then by speed in
        // descending order.

        // Compare the colors.
        int compare;
        compare = String.Compare(this.Color, other.Color, true);

        // If the colors are the same, compare the speeds.
        if (compare == 0)
        {
            compare = this.Speed.CompareTo(other.Speed);

            // Use descending order for speed.
            compare = -compare;
        }

        return compare;
    }
}

Definir una colección personalizada

Se puede definir una colección implementando la interfaz IEnumerable<T> o IEnumerable .Para obtener más información, vea Enumerar una colección y Cómo: Obtener acceso a una clase de colección mediante Foreach (Guía de programación de C#).

Aunque se puede definir una colección personalizada, normalmente es mejor utilizar en su lugar las colecciones que se incluyen en .NET Framework, que se describen en Kinds of Collections anteriormente en este tema.

En el ejemplo siguiente se define una clase de colección personalizada denominada AllColors.Esta clase implementa la interfaz IEnumerable, que requiere que el método GetEnumerator sea implementado.

El método GetEnumerator devuelve una instancia de la clase ColorEnumerator.ColorEnumerator implementa la interfaz IEnumerator, que requiere que la propiedad Current y los métodos MoveNext y Reset estén implementados.

Public Sub ListColors()
    Dim colors As New AllColors()

    For Each theColor As Color In colors
        Console.Write(theColor.Name & " ")
    Next
    Console.WriteLine()
    ' Output: red blue green
End Sub

' Collection class.
Public Class AllColors
    Implements System.Collections.IEnumerable

    Private _colors() As Color =
    {
        New Color With {.Name = "red"},
        New Color With {.Name = "blue"},
        New Color With {.Name = "green"}
    }

    Public Function GetEnumerator() As System.Collections.IEnumerator _
        Implements System.Collections.IEnumerable.GetEnumerator

        Return New ColorEnumerator(_colors)

        ' Instead of creating a custom enumerator, you could
        ' use the GetEnumerator of the array.
        'Return _colors.GetEnumerator
    End Function

    ' Custom enumerator.
    Private Class ColorEnumerator
        Implements System.Collections.IEnumerator

        Private _colors() As Color
        Private _position As Integer = -1

        Public Sub New(ByVal colors() As Color)
            _colors = colors
        End Sub

        Public ReadOnly Property Current() As Object _
            Implements System.Collections.IEnumerator.Current
            Get
                Return _colors(_position)
            End Get
        End Property

        Public Function MoveNext() As Boolean _
            Implements System.Collections.IEnumerator.MoveNext
            _position += 1
            Return (_position < _colors.Length)
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            _position = -1
        End Sub
    End Class
End Class

' Element class.
Public Class Color
    Public Property Name As String
End Class
private void ListColors()
{
    var colors = new AllColors();

    foreach (Color theColor in colors)
    {
        Console.Write(theColor.Name + " ");
    }
    Console.WriteLine();
    // Output: red blue green
}


// Collection class.
public class AllColors : System.Collections.IEnumerable
{
    Color[] _colors =
    {
        new Color() { Name = "red" },
        new Color() { Name = "blue" },
        new Color() { Name = "green" }
    };

    public System.Collections.IEnumerator GetEnumerator()
    {
        return new ColorEnumerator(_colors);

        // Instead of creating a custom enumerator, you could
        // use the GetEnumerator of the array.
        //return _colors.GetEnumerator();
    }

    // Custom enumerator.
    private class ColorEnumerator : System.Collections.IEnumerator
    {
        private Color[] _colors;
        private int _position = -1;

        public ColorEnumerator(Color[] colors)
        {
            _colors = colors;
        }

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return _colors[_position];
            }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            _position++;
            return (_position < _colors.Length);
        }

        void System.Collections.IEnumerator.Reset()
        {
            _position = -1;
        }
    }
}

// Element class.
public class Color
{
    public string Name { get; set; }
}

Iteradores

Un iterador se utiliza para realizar una iteración personalizada en una colección.Un iterador puede ser un método o un descriptor de acceso get .Un iterador utiliza una expresión Yield (Visual Basic) o yield return (C#) para devolver cada elemento de la colección de uno en uno.

Se llama a un iterador mediante una expresión For Each… Next (Visual Basic) o foreach (C#).Cada iteración del bucle For Each llama el iterador.Cuando una expresión Yield o yield return se alcanza en el iterador, se devuelve una expresión y la ubicación actual en el código se conserva.La ejecución se reinicia desde esta ubicación la próxima vez que se llame al iterador.

Para obtener más información, vea Iteradores (C# y Visual Basic).

El ejemplo siguiente utiliza un método de iterador.El método de iterador tiene una expresión Yield o yield return que está dentro de un bucle For… Next (Visual Basic) o for (C#).En el método ListEvenNumbers, cada iteración del cuerpo de la expresión For Each crea una llamada al método de iterador, que continúa a la siguiente expresión Yield o yield return.

Public Sub ListEvenNumbers()
    For Each number As Integer In EvenSequence(5, 18)
        Console.Write(number & " ")
    Next
    Console.WriteLine()
    ' Output: 6 8 10 12 14 16 18
End Sub

Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As IEnumerable(Of Integer)

' Yield even numbers in the range.
    For number = firstNumber To lastNumber
        If number Mod 2 = 0 Then
            Yield number
        End If
    Next
End Function
private void ListEvenNumbers()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    Console.WriteLine();
    // Output: 6 8 10 12 14 16 18
}

private static IEnumerable<int> EvenSequence(
    int firstNumber, int lastNumber)
{
    // Yield even numbers in the range.
    for (var number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}

Vea también

Tareas

Cómo: Obtener acceso a una clase de colección mediante Foreach (Guía de programación de C#)

Referencia

Inicializadores de objeto y de colección (Guía de programación de C#)

Option Strict (Instrucción)

Conceptos

Inicializadores de colección (Visual Basic)

LINQ to Objects

Parallel LINQ (PLINQ)

Seleccionar una clase de colección

Comparaciones y ordenaciones en colecciones

Cuándo utilizar colecciones genéricas

Otros recursos

Mejores prácticas de colecciones

Programar los conceptos

Colecciones y estructuras de datos

Crear y manipular colecciones