Hoy he echado en falta poder definir macros en C#

Pues sí… y no me avergüenzo de decirlo, si hoy C# tuviese algo como el preprocesador de C/C++ me hubiese hecho feliz.

Si lees el por qué C# no soporta macros, tendrás unas cuantas razones por las cuales es una buena idea no usar macros (macros al estilo  #define del preprocesador):

  • Legibilidad: Es obvio que si el código fuente que se compila es distinto que el código fuente que se edita eso lo hace más ininteligible, porque debes «inferir» esas macros para poder entender el código fuente.
  • No respetan las reglas del lenguaje: Las macros tratan el código como texto, no como código y por lo tanto no respetan las reglas del lenguaje, tales como  ámbitos.
  • Son una guarrada: Pues sí, en general lo son. Pero bueno, tampoco nos vamos a poner quisquillosos… hay otras cosas en C# que son una guarrada también y nos callamos.

Pero a pesar de todos esos inconvenientes, a pesar de que debemos evitar usarlas a veces nos pueden sacar de un apuro… precisamente porque tratan el código como texto, no como código 😛

He aquí un ejemplo concreto. Tengo una función definida tal y como sigue:

public static class Check
{
    public static void NotNull<TParameter>(TParameter parameter, string name=null)
        where TParameter : class
    {
        if (parameter == null)
        {
            throw new ArgumentNullException(name ?? nameof(parameter));
        }
    }
}

Vale, ahora quiero que la siguiente línea de código:

Check.NotNull(foo);

Lance una ArgumentNullException, pero quiero que el argumento que se pasa a la excepción sea la cadena «foo» (que es el parámetro que estamos validando).

Yo no sé vosotros, pero a mi no se me ocurre manera de hacerlo. Fijaos que la función «NotNull» lo intenta todo lo bien que sabe: usa nameof(parameter), pero claro nameof(parameter) vale… «parameter». Esta función siempre lanza una ArgumentNullException de «parameter», ya que el nombre de la variable «foo» se pierde totalmente. Es algo totalmente normal.

Por supuesto, si hubiese tenido macros, podría haber hecho algo como lo siguiente (ejemplo en C++):

#define NN(X) NotNull(X, "X")
template <typename T> void NotNull(T const& v, std::string const& arg)
{
  if (v == nullptr) {
    throw std::invalid_argument(arg);
  }
}

int main()
{
  int *a = nullptr;
  NN(a);   // catapum con una std::invalid_argument("a")
}

PD: No estoy pidiendo que se añadan macros en C#, solo que mira… hoy las he echado en falta y he decidido compartirlo con vosotros 😉

5 comentarios sobre “Hoy he echado en falta poder definir macros en C#”

  1. Tal vez se podría sugerir a los de C# que añadieran otro atributo de compilación similar a CallerMemberName (https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute(v=vs.110).aspx). No parece trivial, porque el primer argumento podría ser una expresión compleja…

    En cuanto a las macros, mejor dejarlas que sigan durmiendo ;-). Incluso Stroustrup & Co. siguen añadiéndole cosas a C++ para librarse de ellas.

    Feliz año!

    1. Buenas maestro! 🙂

      >porque el primer argumento podría ser una expresión compleja
      Que es la razón, creo yo, por la que esto no existe ya 🙂
      A fin de cuenta si paso 2+3, ¿cual debe ser el valor obtenido por ese nuevo atributo?

      Y es cierto, en C++ se añaden cada vez más cosas para librarse de las macros. Y es cierto, las macros dan muchos más problemas y es mejor olvidarnos de ellas. De hecho el propio ejemplo que pongo en mi post es solucionable en C#, a costa de un refactoring (usar un atributo [NotNull] vinculado al parámetro en lugar de una llamada Check.NotNull). Pero eso ya es otro refactoring 😉

      El post no pretenía ser un rant, ni como dije, pedir macros… simplemente comentar que tener una herramienta que trate tu código de forma semánticamente distinta, puede tener sus utilidades 😉

  2. Check.NotNull(foo, nameof(foo)); / /???

    Qué pasaría, en caso de poderse hacer lo de c++ en c#, si hago esto:

    Check.NotNull(string null);

    «hay otras cosas en C# que son una guarrada también y nos callamos.»

    Me uno a la petición de una lista de.

  3. “hay otras cosas en C# que son una guarrada también y nos callamos.”

    Una lista de ello?

    //dale loko no me dejes con la curiocidad

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *