Pourquoi n’y a-t-il pas de macros en C #?

Lors de l’apprentissage de C # pour la première fois, j’étais étonné qu’ils n’aient aucun support pour les macros de la même capacité que C / C ++. Je me rends compte que le mot-clé #define existe en C #, mais il manque énormément par rapport à ce que j’ai aimé en C / C ++. Est-ce que quelqu’un sait pourquoi de vraies macros sont absentes de C #?

Je m’excuse si cette question a déjà été posée sous une forme ou une autre – je promets que j’ai passé 5 minutes solides à chercher des doublons avant de les poster.

de la faq C #.

http://blogs.msdn.com/CSharpFAQ/archive/2004/03/09/86979.aspx

Pourquoi C # ne prend-il pas en charge les macros #define? En C ++, je peux définir une macro telle que:

#define PRODUCT(x, y, z) x * y * z

et ensuite l’utiliser dans le code:

int a = PRODUCT(3, 2, 1);

C # ne vous permet pas de faire cela. Pourquoi?

Il y a quelques raisons à cela. Le premier est celui de la lisibilité.

Un de nos principaux objectives de conception pour C # est de garder le code très lisible. Avoir la possibilité d’écrire des macros donne au programmeur la possibilité de créer son propre langage – un langage qui n’a pas nécessairement de rapport avec ce que le code est en dessous. Pour comprendre ce que fait le code, l’utilisateur doit non seulement comprendre le fonctionnement du langage, mais également comprendre toutes les macros #define en vigueur à ce moment-là. Cela rend le code beaucoup plus difficile à lire.

En C #, vous pouvez utiliser des méthodes plutôt que des macros et, dans la plupart des cas, le JIT les incorporera, vous donnant le même aspect de performance.

Il y a aussi un problème un peu plus subtil. Les macros sont faites textuellement, ce qui signifie que si j’écris:

int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)

Je m’attendrais à obtenir quelque chose qui me donne 3 * 7 *11 = 231 , mais en fait, l’expansion que j’ai définie donne:

int y = 1 + 2 * 3 + 4 * 5 + 6;

ce qui me donne 33. Je peux contourner cela par une application judicieuse des parenthèses, mais il est très facile d’écrire une macro qui fonctionne dans certaines situations et pas dans d’autres.

Bien que C # ne soit pas à proprement parler un pré-processeur, il possède des symboles de compilation conditionnels qui peuvent être utilisés pour affecter la compilation. Ceux-ci peuvent être définis dans le code ou avec les parameters du compilateur. Les directives de “prétraitement” en C # (nommées uniquement pour des raisons de cohérence avec C / C ++, bien qu’il n’y ait pas d’étape de prétraitement séparée) sont (texte extrait de la spécification ECMA):

#define and #undef Utilisé pour définir #define and #undef définition des symboles de compilation conditionnels

#if, #elif, #else and #endif

Utilisé pour ignorer certaines sections du code source

#line Permet de contrôler les numéros de ligne émis pour les erreurs et les avertissements.

#error and #warning Utilisé pour émettre des erreurs et des avertissements.

#region and #endregion

Utilisé pour marquer explicitement les sections du code source.

Voir la section 9.5 de la spécification ECMA pour plus d’informations sur ce qui précède. La compilation conditionnelle peut également être effectuée à l’aide de l’atsortingbut Conditional sur une méthode, afin que les appels à la méthode ne soient compilés que lorsque le symbole approprié est défini. Voir la section 24.4.2 de la spécification ECMA pour plus d’informations à ce sujet.

Auteur: Eric Gunnerson

Donc, vous pouvez vous amuser à taper encore et encore.

 // Windows presetation foundation dependency property. public class MyStateControl : ButtonBase { public MyStateControl() : base() { } public Boolean State { get { return (Boolean)this.GetValue(StateProperty); } set { this.SetValue(StateProperty, value); } } public static readonly DependencyProperty StateProperty = DependencyProperty.Register( "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false)); } 

De toute évidence, les concepteurs de C # et de .NET n’utilisent jamais les bibliothèques ou les frameworks qu’ils créent. S’ils le faisaient, ils se rendraient compte qu’une certaine forme de macro système de syntaxe hygiénique est définitivement en ordre.

Ne laissez pas les imperfections des macros boiteuses de C et C ++ vous affecter la puissance du code résolu à la compilation. La résolution du temps de compilation et la génération de code vous permettent d’exprimer plus efficacement le sens et l’intensification du code sans avoir à épeler tous les détails insignifiants du code source. Par exemple, si vous pouviez remplacer ce qui précède par ceci:

 public class MyStateControl : ButtonBase { public MyStateControl() : base() { } [DependencyProperty(DefaultValue=true)] bool State { get; set; } } 

Boo les a, OcamML (au moins Meta ML) les a et C et C ++ les a (sous une forme désagréable, mais mieux que de ne pas les avoir du tout). C # ne le fait pas.

Les macros de style C ++ ajoutent beaucoup de complexité sans les avantages correspondants, selon mon expérience. Je ne les ai certainement pas manqué ni en C # ni en Java. (J’utilise rarement des symboles de préprocesseur en C #, mais je suis parfois content qu’ils soient là.)

Maintenant, diverses personnes ont appelé à des macros de style Lisp , que je connais peu mais qui semblent certainement plus agréables que celles de style C ++.

Qu’est-ce que vous voulez particulièrement faire avec les macros? Nous pouvons peut-être vous aider à penser de manière plus idiomatique C # …

C # est destiné à un public plus large (ou en d’autres termes, base de consommateurs) que C ++, C ou ASM. Le seul moyen d’atteindre cet objective est d’atteindre les programmeurs beaucoup moins qualifiés. Par conséquent, tous les outils puissants mais dangereux sont enlevés. Ie macros, inheritance multiple, contrôle de la durée de vie de l’object ou programmation indépendante du type.

De la même manière, les allumettes, les couteaux et les pistolets à ongles sont utiles et nécessaires, mais ils doivent être tenus hors de scope des enfants. (malheureusement, des incendies criminels, des meurtres, des memory leaks et du code illisible se produisent toujours).

Et avant de m’accuser de ne pas penser à C #, combien de fois as-tu écrit cela:

 protected int _PropOne; public int PropOne { get { return _PropOne; } set { if(value == _PropOne) { return; } NotifyPropertyChanging("PropOne"); _PropOne = value; NotifyPropertyChanged("PropOne"); } } 

Avec les macros, chaque fois que ces 16 lignes ressembleraient à ceci:

 DECLARE_PROPERTY(int, PropOne) DECLARE_PROPERTY(ssortingng, PropTwo) DECLARE_PROPERTY(BitmapImage, PropThree) 

Les macros en C / C ++ ont été utilisées pour définir des constantes, produire de petites fonctions en ligne et pour diverses choses directement liées à la compilation du code (#ifdef).

En C #, vous avez fortement typé les constantes, un compilateur assez intelligent pour intégrer des fonctions lorsque cela est nécessaire, et sait comment comstackr les choses correctement (pas de non-tête précompilée).

Mais il n’y a pas de raison particulière pour laquelle vous ne pouviez pas lancer votre fichier CS via le préprocesseur C si vous le souhaitiez vraiment 🙂

En tant que programmeur C # de longue date, qui est parti apprendre le C ++ pendant un certain temps, je manque maintenant un support riche pour la métaprogrammation C #. Au moins, j’ai maintenant une appréciation plus large de ce que peut signifier la métaprogrammation.

Je voudrais vraiment voir le type de support macro qui est instillé dans Nemerle en C #. Il semble append une capacité d’extension très naturelle et puissante à la langue. Si vous ne l’avez pas regardé, je vous recommande vraiment de le faire.

Il y a de bons exemples sur Wikipedia .

Les macros sont surexploitées en C++ mais elles ont toujours leur utilité , mais la plupart de ces utilisations ne sont pas pertinentes en C# raison de la reflection et de la meilleure utilisation intégrée des exceptions pour le signalement des erreurs.

Cet article compare les macros perl et lisp mais le point est toujours le même: les macros de niveau texte (perl / c ++) causent des problèmes massifs par rapport aux macros de niveau source (lisp)

http://lists.warhead.org.uk/pipermail/iwe/2005-juillet/000130.html

Des gens plus courageux que moi ont lancé leur propre système de macro dans c # http://www.codeproject.com/KB/recipes/prepro.aspx

Les macros sont un outil pour les jours où la plupart des programmeurs étaient plus intelligents que le compilateur. En C / C ++, il y a encore des cas où cela est vrai.

De nos jours, la plupart des programmeurs ne sont pas aussi intelligents que le compilateur / runtime C #.

Quiconque est d’accord avec l’idée que les macros sont mauvaises devrait lire le livre “With Folded Hands”. http://en.wikipedia.org/wiki/With_Folded_Hands Cela raconte comment nous pouvons empêcher les gens de faire des choses stupides au sharepoint les empêcher de faire des choses très sages.

Bien que j’aime C #, je déteste vraiment que cela consortingbue à la stupidification des ingénieurs logiciels réels. Alors, oui, laissez les macros aux professionnels. Pendant que nous y sums, laissez également la désignation des variables aux professionnels. Cela peut créer un code vraiment illisible. Pour suivre l’instruction complète de “code doit être lisible en fin de compte”, toutes les variables doivent être nommées AZ, suivies de az (ou de toute autre construction arbitraire telle que seuls les noms). Parce que certaines personnes non qualifiées peuvent nommer leur variable “SomethingUsefulButNotAllowedByTheComstackrBecauseSomeUsersMayDoDumbThings”.

Vous pouvez faire quelque chose que vous faites avec des macros comme PropertyChanged de cette façon

Si c’est mieux que les macros? C’est une question que vous devez décider 🙂