Types anonymes

Les types anonymes permettent d'encapsuler un ensemble de propriétés en lecture seule dans un unique objet sans avoir à définir explicitement un type. Le nom du type est généré par le compilateur et n'est pas disponible au niveau du code source. Le type de chaque propriété est déduit par le compilateur.

Vous créez des types anonymes en utilisant l’opérateur new avec un initialiseur d’objet. Pour plus d’informations sur les initialiseurs d’objets, consultez Initialiseurs d’objets et de collections.

L'exemple suivant montre un type anonyme qui est initialisé avec deux propriétés nommées Amount et 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);

Les types anonymes sont en règle générale utilisés dans la clause select d’une expression de requête pour retourner un sous-ensemble de propriétés de chaque objet dans la séquence source. Pour plus d'informations sur les requêtes, voir LINQ en C#.

Les types anonymes contiennent une ou plusieurs propriétés en lecture seule publiques. Aucun autre type de membres de classe, tels que des méthodes ou des événements, n'est valide. L'expression qui est utilisée pour initialiser une propriété ne peut pas être null, une fonction anonyme ou un type pointeur.

Le scénario le plus courant consiste à initialiser un type anonyme avec les propriétés d'un autre type. Dans l'exemple suivant, une classe existe qui porte le nom Product. La classe Product comprend des propriétés Color et Price, ainsi que d'autres propriétés qui ne vous intéressent pas. La variable products est une collection d'objets Product. La déclaration de type anonyme commence par le mot clé new. La déclaration initialise un nouveau type qui utilise uniquement deux propriétés de Product. L’utilisation de types anonymes entraîne le retour d’une quantité réduite de données dans la requête.

Si vous n’indiquez pas les noms de membre dans le type anonyme, le compilateur attribue aux membres de type anonyme le même nom que celui de la propriété utilisée pour les initialiser. Vous fournissez un nom pour une propriété qui est initialisée avec une expression, comme indiqué dans l’exemple précédent. Dans l'exemple suivant, les noms des propriétés du type anonyme sont Color et 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);
}

Conseil

Vous pouvez utiliser la règle de style .NET IDE0037 pour indiquer si les noms de membres déduits ou explicites sont préférés.

Il est également possible de définir un champ par objet d’un autre type : classe, struct ou même un autre type anonyme. Pour ce faire, utilisez la variable contenant cet objet comme dans l’exemple suivant, où deux types anonymes sont créés à l’aide de types définis par l’utilisateur déjà instanciés. Dans les deux cas, le champ product du type anonyme shipment et shipmentWithBonus sera de type Product contenant les valeurs par défaut de chaque champ. Et le champ bonus sera de type anonyme créé par le compilateur.

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 };

Quand vous utilisez un type anonyme pour initialiser une variable, vous déclarez la variable en tant que variable locale implicitement typée en utilisant var. Le nom de type ne peut pas être spécifié dans la déclaration de variable, car seul le compilateur a accès au nom sous-jacent du type anonyme. Pour plus d’informations sur var, consultez Variables locales implicitement typées.

Vous pouvez créer un tableau d'éléments typés anonymement en associant une variable locale implicitement typée et un tableau typé implicitement, comme indiqué dans l'exemple suivant.

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

Les types anonymes sont des types class qui dérivent directement de object et qui ne peuvent pas être castés en type à l’exception du type object. Le compilateur fournit un nom pour chaque type anonyme, bien que votre application ne puisse pas y accéder. Du point de vue du CLR, un type anonyme n'est pas différent des autres types de référence.

Si plusieurs initialiseurs d'objet dans un assembly spécifient une séquence de propriétés dans le même ordre et qui sont du même type et portent le même nom, le compilateur traite les objets comme des instances du même type. Elles partagent les mêmes informations de type générées par le compilateur.

Les types anonymes prennent en charge la mutation non destructrice sous la forme d’expressions. Cela vous permet de créer une instance d’un type anonyme où une ou plusieurs propriétés ont de nouvelles valeurs :

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

Vous ne pouvez pas déclarer un champ, une propriété, un événement ou le type de retour d'une méthode comme ayant un type anonyme. De même, vous ne pouvez pas déclarer un paramètre formel d'une méthode, d'une propriété, d'un constructeur ou d'un indexeur comme ayant un type anonyme. Pour passer un type anonyme, ou une collection qui contient des types anonymes, en tant qu'argument d'une méthode, vous pouvez déclarer le paramètre comme object de type. Toutefois, l’utilisation de object pour les types anonymes va à l’encontre de l’objectif d’un typage fort. Si vous devez stocker les résultats de requête ou les passer en dehors des limites de la méthode, utilisez un struct ordinaire ou une classe au lieu d'un type anonyme.

Dans la mesure où les méthodes Equals et GetHashCode dans les types anonymes sont définies selon les termes des méthodes Equals et GetHashCode des propriétés, deux instances du même type anonyme sont égales si toutes leurs propriétés sont égales.

Remarque

Le niveau d’accessibilité d’un type anonyme est internal, donc deux types anonymes définis dans différents assemblys ne sont pas du même type. Par conséquent, les instances de types anonymes ne peuvent pas être égales lorsqu’elles sont définies dans différents assemblys, même si toutes leurs propriétés sont égales.

Les types anonymes remplacent la méthode ToString, en concaténant le nom et la sortie ToString de chaque propriété entourée d’accolades.

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

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