Tipos anónimos

Los tipos anónimos son una manera cómoda de encapsular un conjunto de propiedades de solo lectura en un único objeto sin tener que definir primero un tipo explícitamente. El compilador genera el nombre del tipo y no está disponible en el nivel de código fuente. El compilador deduce el tipo de cada propiedad.

Para crear tipos anónimos, use el operador new con un inicializador de objeto. Para obtener más información sobre los inicializadores de objeto, vea Inicializadores de objeto y colección (Guía de programación de C#).

En el ejemplo siguiente se muestra un tipo anónimo que se inicializa con dos propiedades llamadas Amount y Message.

var v = new { Amount = 108, Message = "Hello" };

// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);

Los tipos anónimos suelen usarse en la cláusula select de una expresión de consulta para devolver un subconjunto de las propiedades de cada objeto en la secuencia de origen. Para más información sobre las consultas, vea LINQ en C#.

Los tipos anónimos contienen una o varias propiedades públicas de solo lectura. No es válido ningún otro tipo de miembros de clase, como métodos o eventos. La expresión que se usa para inicializar una propiedad no puede ser null, una función anónima o un tipo de puntero.

El escenario más habitual es inicializar un tipo anónimo con propiedades de otro tipo. En el siguiente ejemplo, se da por hecho que existe una clase con el nombre Product. La clase Product incluye las propiedades Color y Price, junto con otras propiedades que no son de su interés. La variable products es una colección de objetos Product. La declaración de tipo anónimo comienza con la palabra clave new. La declaración inicializa un nuevo tipo que solo usa dos propiedades de Product. El uso de tipos anónimos hace que la consulta devuelva una cantidad de datos menor.

Si no especifica nombres de miembros en el tipo anónimo, el compilador da a los miembros de este tipo el nombre de la propiedad que se usa para inicializarlos. Debe proporcionar un nombre para una propiedad que se está inicializando con una expresión, como se muestra en el ejemplo anterior. En el siguiente ejemplo, los nombres de las propiedades del tipo anónimo son Color y Price.

var productQuery =
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

Sugerencia

Puede usar la regla de estilo de .NET IDE0037 para aplicar si se prefieren los nombres de miembros inferidos o explícitos.

También es posible definir un campo por objeto de otro tipo: clase, estructura o incluso otro tipo anónimo. Se realiza mediante el uso de la variable que contiene este objeto igual que en el ejemplo siguiente, donde se crean dos tipos anónimos mediante tipos definidos por el usuario para los que ya se han creado instancias. En ambos casos, el campo product del tipo anónimo shipment y shipmentWithBonus será de tipo Product que contiene los valores predeterminados de cada campo. Y el campo bonus será de tipo anónimo creado por el compilador.

var product = new Product();
var bonus = new { note = "You won!" };
var shipment = new { address = "Nowhere St.", product };
var shipmentWithBonus = new { address = "Somewhere St.", product, bonus };

Normalmente, cuando se usa un tipo anónimo para inicializar una variable, la variable se declara como variable local con tipo implícito mediante var. El nombre del tipo no se puede especificar en la declaración de la variable porque solo el compilador tiene acceso al nombre subyacente del tipo anónimo. Para obtener más información sobre var, vea Variables locales con asignación implícita de tipos.

Puede crear una matriz de elementos con tipo anónimo combinando una variable local con tipo implícito y una matriz con tipo implícito, como se muestra en el ejemplo siguiente.

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

Los tipos anónimos son tipos class que derivan directamente de object y que no se pueden convertir a ningún tipo excepto object. El compilador proporciona un nombre para cada tipo anónimo, aunque la aplicación no pueda acceder a él. Desde el punto de vista de Common Language Runtime, un tipo anónimo no es diferente de otros tipos de referencia.

Si dos o más inicializadores de objeto anónimo en un ensamblado especifican una secuencia de propiedades que están en el mismo orden y que tienen los mismos nombres y tipos, el compilador trata el objeto como instancias del mismo tipo. Comparten la misma información de tipo generada por el compilador.

Los tipos anónimos admiten la mutación no destructiva en forma de con expresiones. Esto le permite crear una nueva instancia de un tipo anónimo en el que una o varias propiedades tienen nuevos valores:

var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);

No se puede declarar que un campo, una propiedad, un evento o el tipo de valor devuelto de un método tengan un tipo anónimo. De forma similar, no se puede declarar que un parámetro formal de un método, propiedad, constructor o indizador tenga un tipo anónimo. Para pasar un tipo anónimo, o una colección que contiene tipos anónimos, como un argumento a un método, puede declarar el parámetro como object de tipo. Sin embargo, el uso de object para tipos anónimos anula el propósito de la coincidencia segura. Si tiene que almacenar resultados de consulta o pasarlos fuera del límite del método, considere la posibilidad de usar un struct o una clase con nombre normal en lugar de un tipo anónimo.

Como los métodos Equals y GetHashCode de tipos anónimos se definen en términos de los métodos Equals y GetHashCode de las propiedades, dos instancias del mismo tipo anónimo son iguales solo si todas sus propiedades son iguales.

Nota:

El nivel de accesibilidad de un tipo anónimo es internal; por tanto, dos tipos anónimos definidos en ensamblados diferentes no son del mismo tipo. Por tanto, las instancias de tipos anónimos no pueden ser iguales entre sí cuando se definen en ensamblados diferentes, incluso cuando todas sus propiedades son iguales.

Los tipos anónimos invalidan el método ToString, concatenando el nombre y la salida ToString de cada propiedad rodeada de llaves.

var v = new { Title = "Hello", Age = 24 };

Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"