Inicializadores de objeto y de colección (Guía de programación de C#)Object and Collection Initializers (C# Programming Guide)

C# permite crear instancias de un objeto o colección y realizar asignaciones de miembros en una sola instrucción.C# lets you instantiate an object or collection and perform member assignments in a single statement.

Inicializadores de objetoObject initializers

Los inicializadores de objeto permiten asignar valores a cualquier campo o propiedad accesible de un objeto en el momento de su creación sin tener que invocar un constructor seguido de líneas de instrucciones de asignación.Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. La sintaxis de inicializador de objetos permite especificar argumentos para un constructor u omitir los argumentos (y la sintaxis de paréntesis).The object initializer syntax enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). En el ejemplo siguiente se muestra cómo usar un inicializador de objeto con un tipo con nombre, Cat, y cómo invocar el constructor predeterminado.The following example shows how to use an object initializer with a named type, Cat and how to invoke the default constructor. Tenga en cuenta el uso de propiedades implementadas automáticamente en la clase Cat.Note the use of auto-implemented properties in the Cat class. Para obtener más información, vea Propiedades implementadas automáticamente.For more information, see Auto-Implemented Properties.

public class Cat
{
    // Auto-implemented properties.
    public int Age { get; set; }
    public string Name { get; set; }

    public Cat()
    {
    }

    public Cat(string name)
    {
        this.Name = name;
    }
}
Cat cat = new Cat { Age = 10, Name = "Fluffy" };
Cat sameCat = new Cat("Fluffy"){ Age = 10 };

La sintaxis de los inicializadores de objeto le permite crear una instancia, y después asigna el objeto recién creado, con las propiedades asignadas, a la variable de la asignación.The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment.

A partir de C# 6, los inicializadores de objeto pueden establecer indizadores, además de asignar campos y propiedades.Starting with C# 6, object initializers can set indexers, in addition to assigning fields and properties. Tenga en cuenta esta clase básica Matrix:Consider this basic Matrix class:

public class Matrix
{
    private double[,] storage = new double[3, 3];

    public double this[int row, int column]
    {
        // The embedded array will throw out of range exceptions as appropriate.
        get { return storage[row, column]; }
        set { storage[row, column] = value; }
    }
}

Se podría inicializar la matriz de identidad con el código siguiente:You could initialize the identity matrix with the following code:

var identity = new Matrix
{
    [0, 0] = 1.0,
    [0, 1] = 0.0,
    [0, 2] = 0.0,

    [1, 0] = 0.0,
    [1, 1] = 1.0,
    [1, 2] = 0.0,

    [2, 0] = 0.0,
    [2, 1] = 0.0,
    [2, 2] = 1.0,
};

Puede usarse cualquier indizador accesible que contenga un establecedor accesible como una de las expresiones de un inicializador de objeto, independientemente del número o los tipos de argumentos.Any accessible indexer that contains an accessible setter can be used as one of the expressions in an object initializer, regardless of the number or types of arguments. Los argumentos del índice forman el lado izquierdo de la asignación, mientras que el valor es el lado derecho de la expresión.The index arguments form the left side of the assignment, and the value is the right side of the expression. Por ejemplo, todos estos son válidos si IndexersExample tiene los indizadores adecuados:For example, these are all valid if IndexersExample has the appropriate indexers:

var thing = new IndexersExample {
    name = "object one",
    [1] = '1',
    [2] = '4',
    [3] = '9',
    Baz = Math.PI,
    ['C',4] = "Middle C"
}

Para que el código anterior se compile, el tipo IndexersExample debe tener los siguientes miembros:For the preceding code to compile, the IndexersExample type must have the following members:

public string name;
public double Size { set { ... }; }
public char this[int i] { set { ... }; }
public string this[char c, int i] {  set { ... }; }
}

Inicializadores de objeto con tipos anónimosObject Initializers with anonymous types

Aunque los inicializadores de objeto se pueden usar en cualquier contexto, resultan especialmente útiles en las expresiones de consulta LINQLINQ.Although object initializers can be used in any context, they are especially useful in LINQLINQ query expressions. Las expresiones de consulta usan con frecuencia tipos anónimos, que solo se pueden inicializar con un inicializador de objeto, como se muestra en la siguiente declaración.Query expressions make frequent use of anonymous types, which can only be initialized by using an object initializer, as shown in the following declaration.

var pet = new { Age = 10, Name = "Fluffy" };  

Los tipos anónimos permiten a la cláusula select de una expresión de consulta LINQLINQ transformar objetos de la secuencia original en objetos cuyo valor y forma pueden ser distintos de los originales.Anonymous types enable the select clause in a LINQLINQ query expression to transform objects of the original sequence into objects whose value and shape may differ from the original. Esto resulta útil si desea almacenar solo una parte de la información de cada objeto en una secuencia.This is useful if you want to store only a part of the information from each object in a sequence. En el ejemplo siguiente, suponga que un objeto del producto (p) contiene numerosos campos y métodos y que solo le interesa crear una secuencia de objetos que contenga el nombre del producto y el precio por unidad.In the following example, assume that a product object (p) contains many fields and methods, and that you are only interested in creating a sequence of objects that contain the product name and the unit price.

var productInfos =
    from p in products
    select new { p.ProductName, p.UnitPrice };

Al ejecutarse esta consulta, la variable productInfos incluirá una secuencia de objetos a la que se puede tener acceso en una instrucción foreach, como se muestra en este ejemplo:When this query is executed, the productInfos variable will contain a sequence of objects that can be accessed in a foreach statement as shown in this example:

foreach(var p in productInfos){...}  

Cada objeto del nuevo tipo anónimo tiene dos propiedades públicas que reciben los mismos nombres que las propiedades o los campos del objeto original.Each object in the new anonymous type has two public properties that receive the same names as the properties or fields in the original object. También puede cambiar el nombre de un campo al crear un tipo anónimo; en el ejemplo siguiente se cambia el nombre del campo UnitPrice a Price.You can also rename a field when you are creating an anonymous type; the following example renames the UnitPrice field to Price.

select new {p.ProductName, Price = p.UnitPrice};  

Inicializadores de colecciónCollection initializers

Los inicializadores de colección le permiten especificar uno o varios inicializadores de elemento al inicializar un tipo de colección que implementa IEnumerable y tiene Add con la firma apropiada como un método de instancia o un método de extensión.Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method. Los inicializadores de elemento pueden ser un valor simple, una expresión o un inicializador de objeto.The element initializers can be a simple value, an expression, or an object initializer. Si se usa un inicializador de colección, no es necesario especificar varias llamadas; el compilador las agrega automáticamente.By using a collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically.

En el ejemplo siguiente se muestran dos inicializadores de colección simples:The following example shows two simple collection initializers:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };  

El inicializador de colección siguiente usa inicializadores de objeto para inicializar los objetos de la clase Cat definida en un ejemplo anterior.The following collection initializer uses object initializers to initialize objects of the Cat class defined in a previous example. Observe que los inicializadores de objeto individuales se escriben entre llaves y se separan por comas.Note that the individual object initializers are enclosed in braces and separated by commas.

List<Cat> cats = new List<Cat>
{
    new Cat{ Name = "Sylvester", Age=8 },
    new Cat{ Name = "Whiskers", Age=2 },
    new Cat{ Name = "Sasha", Age=14 }
};

Puede especificar null como elemento de un inicializador de colección si el método Add de la colección lo permite.You can specify null as an element in a collection initializer if the collection's Add method allows it.

List<Cat> moreCats = new List<Cat>
{
    new Cat{ Name = "Furrytail", Age=5 },
    new Cat{ Name = "Peaches", Age=4 },
    null
};

Puede especificar elementos indexados si la colección admite indexación de lectura y escritura.You can specify indexed elements if the collection supports read / write indexing.

var numbers = new Dictionary<int, string>
{
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};

El ejemplo anterior genera código que llama a Item[TKey] para establecer los valores.The preceding sample generates code that calls the Item[TKey] to set the values. A partir de C# 6, puede inicializar diccionarios y otros contenedores asociativos con la siguiente sintaxis.Beginning with C# 6, you can initialize dictionaries and other associative containers using the following syntax. Tenga en cuenta que en lugar de sintaxis de indizador, con paréntesis y una asignación, usa un objeto con varios valores:Notice that instead of indexer syntax, with parentheses and an assignment, it uses an object with multiple values:

var moreNumbers = new Dictionary<int, string>
{
    {19, "nineteen" },
    {23, "twenty-three" },
    {42, "forty-two" }
};

Este ejemplo de inicializador llama a Add(TKey, TValue) para agregar los tres elementos al diccionario.This initializer example calls Add(TKey, TValue) to add the three items into the dictionary. Estas dos maneras distintas de inicializar colecciones asociativas tienen un comportamiento ligeramente diferente debido a las llamadas a métodos que genera el compilador.These two different ways to initialize associative collections have slightly different behavior because of the method calls the compiler generates. Ambas variantes funcionan con la clase Dictionary.Both variants work with the Dictionary class. Es posible que otros tipos solo admitan una o la otra, en función de su API pública.Other types may only support one or the other based on their public API.

EjemplosExamples

En el ejemplo siguiente se combinan los conceptos de inicializadores de objeto y colección.The following example combines the concepts of object and collection initializers.

public class InitializationSample
{
    public class Cat
    {
        // Auto-implemented properties.
        public int Age { get; set; }
        public string Name { get; set; }

        public Cat() { }

        public Cat(string name)
        {
            Name = name;
        }
    }

    public static void Main()
    {
        Cat cat = new Cat { Age = 10, Name = "Fluffy" };
        Cat sameCat = new Cat("Fluffy"){ Age = 10 };

        List<Cat> cats = new List<Cat>
        {
            new Cat { Name = "Sylvester", Age = 8 },
            new Cat { Name = "Whiskers", Age = 2 },
            new Cat { Name = "Sasha", Age = 14 }
        };

        List<Cat> moreCats = new List<Cat>
        {
            new Cat { Name = "Furrytail", Age = 5 },
            new Cat { Name = "Peaches", Age = 4 },
            null
        };

        // Display results.
        System.Console.WriteLine(cat.Name);

        foreach (Cat c in cats)
            System.Console.WriteLine(c.Name);

        foreach (Cat c in moreCats)
            if (c != null)
                System.Console.WriteLine(c.Name);
            else
                System.Console.WriteLine("List element has null value.");
    }
    // Output:
    //Fluffy
    //Sylvester
    //Whiskers
    //Sasha
    //Furrytail
    //Peaches
    //List element has null value.
}

El ejemplo siguiente muestra un objeto que implementa IEnumerable y que contiene un método Add con varios parámetros. Usa un inicializador de colección con varios elementos por cada elemento de la lista correspondiente a la firma del método Add.The following example shows an object that implements IEnumerable and contains an Add method with multiple parameters, It uses a collection initializer with multiple elements per item in the list that correspond to the signature of the Add method.

    public class FullExample
    { 
        class FormattedAddresses : IEnumerable<string>
        {
            private List<string> internalList = new List<string>();
            public IEnumerator<string> GetEnumerator() => internalList.GetEnumerator();

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalList.GetEnumerator();

            public void Add(string firstname, string lastname, 
                string street, string city, 
                string state, string zipcode) => internalList.Add(
                $@"{firstname} {lastname}
{street}
{city}, {state} {zipcode}"
                );
        }

        public static void Main()
        {
            FormattedAddresses addresses = new FormattedAddresses()
            {
                {"John", "Doe", "123 Street", "Topeka", "KS", "00000" },
                {"Jane", "Smith", "456 Street", "Topeka", "KS", "00000" }
            };

            Console.WriteLine("Address Entries:");

            foreach (string addressEntry in addresses)
            {
                Console.WriteLine("\r\n" + addressEntry);
            }
        }

        /*
         * Prints:
         
            Address Entries:

            John Doe
            123 Street
            Topeka, KS 00000

            Jane Smith
            456 Street
            Topeka, KS 00000
         */
    }

Los métodos Add pueden usar la palabra clave params para tomar un número variable de argumentos, como se muestra en el ejemplo siguiente.Add methods can use the params keyword to take a variable number of arguments, as shown in the following example. En este ejemplo además se muestra la implementación personalizada de un indizador para inicializar una colección mediante índices.This example also demonstrates the custom implementation of an indexer to initialize a collection using indexes.

public class DictionaryExample
{ 
    class RudimentaryMultiValuedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, List<TValue>>>
    {
        private Dictionary<TKey, List<TValue>> internalDictionary = new Dictionary<TKey, List<TValue>>();

        public IEnumerator<KeyValuePair<TKey, List<TValue>>> GetEnumerator() => internalDictionary.GetEnumerator();

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalDictionary.GetEnumerator();

        public List<TValue> this[TKey key]
        {
            get => internalDictionary[key];
            set => Add(key, value);
        }

        public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable<TValue>)values);

        public void Add(TKey key, IEnumerable<TValue> values)
        {
            if (!internalDictionary.TryGetValue(key, out List<TValue> storedValues))
                internalDictionary.Add(key, storedValues = new List<TValue>());

            storedValues.AddRange(values);
        }
    }

    public static void Main()
    {
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary1
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", "Bob", "John", "Mary" },
                {"Group2", "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary2
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                ["Group1"] = new List<string>() { "Bob", "John", "Mary" },
                ["Group2"] = new List<string>() { "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary3
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", new string []{ "Bob", "John", "Mary" } },
                { "Group2", new string[]{ "Eric", "Emily", "Debbie", "Jesse" } }
            };

        Console.WriteLine("Using first multi-valued dictionary created with a collection initializer:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary1)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }

        Console.WriteLine("\r\nUsing second multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary2)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
        Console.WriteLine("\r\nUsing third multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary3)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
    }

    /*
     * Prints:
     
        Using first multi-valued dictionary created with a collection initializer:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using second multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using third multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse
     */
}

Vea tambiénSee also