Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí
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 😉