c# .net macros c-preprocessor

¿Por qué no hay macros en C#?



.net c-preprocessor (11)

C # está dirigido a una audiencia más amplia (o en otro término, base de consumidores) que C ++, C o ASM. La única forma de lograr este objetivo es llegar a los programadores considerablemente menos capacitados. Por lo tanto, todas las herramientas poderosas pero peligrosas son quitadas. Es decir, macros, herencia múltiple, control sobre la duración del objeto o programación de tipo independiente.

De la misma manera, los fósforos, los cuchillos y las pistolas de clavos son útiles y necesarios, pero deben mantenerse fuera del alcance de los niños. (lamentablemente, aún ocurren incendios, asesinatos, pérdidas de memoria y códigos ilegibles).

Y antes de acusarme de no pensar C #, ¿cuántas veces has escrito eso?

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

Con macros, cada vez que esas 16 líneas se verían así:

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

Al aprender C # por primera vez, me sorprendió que no tuvieran soporte para macros en la misma capacidad que existe en C / C ++. Me doy cuenta de que la palabra clave #define existe en C #, pero es muy deficiente en comparación con lo que creí amar en C / C ++. ¿Alguien sabe por qué faltan macros reales de C #?

Me disculpo si esta pregunta ya se ha hecho de alguna forma u otra. Prometo haber gastado 5 minutos sólidos buscando duplicados antes de publicarlos.


Como programador de C # durante mucho tiempo que se fue a aprender C ++ por un tiempo, ahora echo de menos el rico soporte para la metaprogramación de C #. Al menos, ahora tengo una apreciación más amplia de lo que puede significar la metaprogramación.

Realmente me gustaría ver el tipo de soporte macro que se inculca en Nemerle en C #. Parece agregar una capacidad de extensión muy natural y poderosa al lenguaje. Si no lo ha mirado, realmente recomiendo hacerlo.

Hay algunos buenos ejemplos en Wikipedia .


Cualquiera que esté de acuerdo con la idea de que las macros son malas debería leer el libro "Con las manos dobladas". http://en.wikipedia.org/wiki/With_Folded_Hands Cuenta una historia sobre cómo podemos evitar que las personas hagan cosas estúpidas hasta el punto de evitar que hagan cosas muy sabias.

Mientras me gusta C #, realmente odio que contribuya a la estupidez de los ingenieros de software reales. Entonces, sí, deje macros a los profesionales. Mientras estamos en ello, deje la denominación de variables a los profesionales también. Eso puede generar un código realmente ilegible. Para seguir la declaración completa de "el código debe ser legible en última instancia", todas las variables deben llamarse AZ, seguidas por az (o algún otro constructo arbitrario como solo los sustantivos). Porque algunas personas no calificadas pueden nombrar su variable "SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings".



Las macros de estilo C ++ agregan una gran cantidad de complejidad sin el correspondiente beneficio, en mi experiencia. Ciertamente no los extrañé ni en C # ni en Java. (Raramente utilizo símbolos de preprocesador en C #, pero a veces me alegra que estén allí).

Ahora, varias personas han pedido macros al estilo de Lisp , de las que sé poco, pero que ciertamente suenan bastante más agradables que las de estilo C ++.

¿Qué quiere hacer particularmente con las macros? Es posible que podamos ayudarte a pensar de una manera más idiomáticamente C # ...


Las macros en C / C ++ se usaron para definir constantes, producir pequeñas funciones en línea y para varias cosas directamente relacionadas con la compilación del código (#ifdef).

En C #, tiene constantes fuertemente tipadas, un compilador suficientemente inteligente para las funciones en línea cuando es necesario, y sabe cómo compilar las cosas de la manera correcta (sin tonterías precompiladas en el encabezado).

Pero no hay una razón particular por la que no puedas ejecutar tu archivo CS a través del preprocesador C primero si realmente lo deseas :)


Las macros se usan en exceso en C++ pero todavía tienen sus usos , sin embargo, la mayoría de estos usos no son relevantes en C# debido a la reflexión y al mejor uso integrado de excepciones para el informe de errores.


Las macros son una herramienta para los días en que la mayoría de los programadores eran más inteligentes que el compilador. En C / C ++, todavía hay algunos casos en que esto es cierto.

Hoy en día, la mayoría de los programadores no son tan inteligentes como el compilador / tiempo de ejecución de C #.


Para que pueda divertirse escribiendo ESTO una y otra vez.

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

Obviamente, los diseñadores de C # y .NET nunca utilizan realmente ninguna de las bibliotecas o marcos que crean. Si lo hicieran, se darían cuenta de que alguna forma de sistema macro sintáctico hygénico está definitivamente en orden.

No permita que las deficiencias de las macros cojo de C y C ++ lo amarguen con el poder del código de tiempo de compilación resuelto. La resolución de tiempo de compilación y la generación de código le permite expresar de manera más efectiva el SIGNIFICADO y la INTENCIÓN del código sin tener que especificar todos los detalles molestos del código fuente. Por ejemplo, ¿y si pudieras reemplazar lo anterior con esto?

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

Boo los tiene, OcamML (al menos Meta ML) los tiene, y C y C ++ los tiene (en una forma desagradable, pero es mejor que no tenerlos en absoluto). C # no.


Puedes hacer algo que haces con macros como PropertyChanged con formas como this

Si eso es mejor que las macros? Esa es una pregunta que USTED debe decidir :)


de C # faq.

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

¿Por qué C # no admite #define macros? En C ++, puedo definir una macro como:

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

y luego usarlo en el código:

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

C # no te permite hacer esto. ¿Por qué?

Hay algunas razones por qué. El primero es uno de legibilidad.

Una de nuestras principales metas de diseño para C # es mantener el código muy legible. Tener la capacidad de escribir macros le da al programador la posibilidad de crear su propio idioma, uno que no necesariamente guarda relación con el código subyacente. Para comprender lo que hace el código, el usuario no solo debe comprender cómo funciona el lenguaje, sino que también debe comprender todas las macros #define que están vigentes en ese momento. Eso hace que el código sea mucho más difícil de leer.

En C #, puede usar métodos en lugar de macros, y en la mayoría de los casos, el JIT los alineará, proporcionándole el mismo aspecto de rendimiento.

También hay un problema algo más sutil. Las macros se hacen textualmente, lo que significa que si escribo:

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

Esperaría obtener algo que me dé 3 * 7 *11 = 231 , pero de hecho, la expansión tal como la he definido me da:

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

lo que me da 33. Puedo evitarlo mediante una aplicación juiciosa de paréntesis, pero es muy fácil escribir una macro que funciona en algunas situaciones y no en otras.

Aunque C # no tiene un pre-procesador estrictamente hablando, sí tiene símbolos de compilación condicionales que pueden usarse para afectar la compilación. Estos se pueden definir dentro del código o con parámetros para el compilador. Las directivas de "preprocesamiento" en C # (nombradas únicamente por coherencia con C / C ++, a pesar de no haber un paso de preprocesamiento por separado) son (texto tomado de la especificación ECMA):

#define and #undef Utilizados para definir y definir los símbolos de compilación condicionales

#if, #elif, #else and #endif

Se usa para saltear condicionalmente secciones del código fuente

#line Se usa para controlar los números de línea emitidos por errores y advertencias.

#error and #warning Usados ​​para emitir errores y advertencias.

#region and #endregion

Se usa para marcar explícitamente secciones del código fuente.

Consulte la sección 9.5 de la especificación ECMA para obtener más información sobre lo anterior. La compilación condicional también se puede lograr utilizando el atributo Condicional en un método, de modo que las llamadas al método solo se compilarán cuando se defina el símbolo apropiado. Consulte la sección 24.4.2 de la especificación de ECMA para obtener más información al respecto.

Autor: Eric Gunnerson