Avec l’arrivée de C# 3.0, les équipes de développement Microsoft nous propose un panel généreux de nouveautés. Toutes ces nouveautés sont dans la lignée de celles proposées dans la version 2.0 (types génériques, itérateurs, méthodes anonymes ou encore Nullable), qui, soyons en certains, n’était qu’une étape. Cette version dévoile enfin les intentions de Microsoft, et tous ces nouveaux concepts ont bien une finalité. Mais ne soyons pas trop empressés, et ne dévoilons pas d’ores et déjà la fin.

Pour mémoire, rappelons que C# a été conçu pour révéler au maximum les problèmes à la compilation, ce qui en fait un langage strict mais sûr.

Propriétés simplifiées

Une première nouveauté permet de déclarer une propriété plus simplement. Ainsi, il n’est plus nécessaire de créer le champ privé, puisqu’il est automatiquement généré par le compilateur. Le fait de définir l’une des méthodes get ou set en privée rend respectivement la propriété writeonly ou readonly.

Initialiseurs d’objets

L’initialiseur d’objets est une forme syntaxique permettant de d’initialiser les propriétés d’un objet en passant par le constructeur par défaut. Elle remplace l’appel à un constructeur surchargé que l’on aurait créé. Ainsi, le compilateur va créer de manière sûre l’objet instancié : la référence vers l’objet ne sera attribuée qu’une fois toutes les propriétés initialisées. Pour cela, le compilateur va créer une variable temporaire, dont le développeur ne connait pas l’existence, et va ensuite assigner la référence vers l’objet créé à la variable définitive, déclarée par le développeur. Cette nouveauté permet notamment de simplifier la construction de collections, dont les éléments sont connus.

Inférence de type

Il est très commun d’associer la déclaration d’une variable à son initialisation. Cette dernière étape permet à elle seule et sans ambigüité de déterminer le type de l’instance ainsi créée. Dans C# 3.0, il n’est donc plus nécessaire de préciser le type d’une variable lors de son initialisation. On emploiera alors le mot clé var, lors de la déclaration, indiquant ainsi au compilateur de déterminer lui-même le type. L’IntelliSense est également capable de faire ce travail, et de proposer naturellement toutes les propriétés et méthodes de l’objet créé. Attention, l’inférence de type ne fonctionne que pour les variables locales, puisqu’il est nécessaire de les instancier à la déclaration.

Types anonymes

Il est courant de devoir consolider des données provenant de plusieurs objets pour permettre un traitement. Au-delà de 4 ou 5 paramètres, les normes imposent de passer par une structure (classe ou struct). Cela oblige donc le développeur à créer des structures complémentaires, sans réel intérêt dans le modèle objet. Pour palier à ce problème, il est désormais possible de créer dynamiquement un type anonyme. Par définition, il ne possède pas de nom et n’a donc pas vocation à être réutilisé. L’inférence de type permet de récupérer une instance de ce type anonyme et le manipuler comme n’importe quelle autre instance de classe. Le compilateur crée automatiquement la classe manquante, simplifiant ainsi le travail du développeur, tandis que l’IntelliSense permet sans difficulté d’accéder aux propriétés de l’objet. En effet, il n’est pas prévu d’associer des méthodes à ce nouveau type. Associé à l’inférence de types et à l’initialiseur d’objet, l’utilisation d’un type anonyme permet d’écrire :

var employee = new {Nom="Guacamole", Prenom="Mathilde"};

Méthodes d’extensions

Comme leur nom l’indique, les méthodes d’extensions permettent d’étendre les fonctionnalités d’une classe. L’héritage n’est, en effet, pas toujours très adapté pour une telle utilisation et est d’avantage conçu pour la spécialisation. Étendre une classe est donc désormais possible en passant par une classe statique, dans laquelle on déclare comme statiques un certain nombre de méthodes d’extensions. Le rapport entre une méthode d’extension et la classe qu’elle étend se situe au niveau du premier paramètre de la méthode. Le paramètre est ainsi précédé du mot clé this et son type correspond à la classe étendue. Il est alors possible d’appeler la méthode d’extension directement sur une instance de la classe étendue, en utilisant le point. L’IntelliSense est également capable de proposer les méthodes d’extension. Notons que les méthodes d’extension peuvent également s’appliquer aux interfaces, et pas seulement aux classes.

Lambdas expressions

En C# 2.0, on connaissait les méthodes anonymes. À peine le temps de les apprivoiser, et voici les lambdas expressions : une simplification syntaxique des méthodes anonymes. Les lambdas expressions vont cependant bien au-delà, puisqu’elles permettent de définir de véritables expressions, comportant des paramètres, et évaluables de manière différée. Les lambda expressions peuvent être compilées directement en IL, ou bien encore faire l’objet d’une transformation, par exemple en SQL.

Plus loin …

En introduction, nous soulignions à la fois la complémentarité entre les nouveautés du langage de C# 2.0 et de C# 3.0, et le fait qu’elles aient toutes une même finalité cachée. Et après toutes les avoir parcourues, nous pouvons enfin révéler ce secret de polichinelle : il ne s’agit ni plus ni moins que de LINQ ! Ce qu’il faut réellement comprendre, donc, c’est que LINQ est l’aboutissement de toutes ces nouveautés. Sans elles, LINQ n’aurait pas été possible. Au risque de perturber, voire de larguer, une majorité des développeurs, Microsoft et ses équipes de développement ont donc investi énormément sur cette nouvelle fonctionnalité du framework. Voici donc la réponse à ceux qui accusaient Microsoft de tout recopier sur Java ! Microsoft a compris qu’il fallait s’inspirer de ce qui se fait de mieux dans les différents langages pour construire sa plateforme. Enfin, gageons que cet investissement important porte ses fruits, en facilitant l’adoption de la plateforme .NET, et en permettant à cette technologie de séduire de nouveaux clients.

Billets sur le même thème