Uso de Caller Information en .NET
Veo, en no pocos proyectos, el uso de textos hardcodeados o constantes con los nombres de los métodos y algunas cosas más, y que se utiliza para escribir información en el log, en pantalla, en una excepción, o en otra parte del código.
En C# 5.0 y .NET Framework 4.5 se introdujeron unos atributos denominados Caller Information y que pertenecen al namespace System.Runtime.CompilerServices.
Sin embargo, mucha gente lo obvia y no lo usa (sus razones tendrá, pero que no sea una de ellas por no saber que existen).
Lo destacable de estos atributos es que no es necesario pasar ningún argumento con el nombre del método, etc., porque CompilerServices hace ese trabajo por nosotros, y nos nutre de importante información.
Información que un DevOps puede analizar con Application Insights por ejemplo, u otra herramienta.
Pero veamos un sencillo ejemplo práctico de cómo funciona esto.
El siguiente proyecto, escribe en pantalla información como el nombre del método, el fichero de código que contiene el método ejecutado, y la línea de código en la que se produce.
public class Program { public static void Main(string[] args) { Console.WriteLine("Started"); Console.WriteLine(); TraceWriteLine("I'm Main"); FooMethod(); Console.WriteLine(); Console.WriteLine("Press any key to close"); Console.ReadKey(); } private static void TraceWriteLine(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { Console.WriteLine($"{DateTime.UtcNow}"); Console.WriteLine($"message: {message}"); Console.WriteLine($"member name: {memberName}"); Console.WriteLine($"source file path: {sourceFilePath}"); Console.WriteLine($"source line number: {sourceLineNumber}"); Console.WriteLine(String.Empty); } private static void FooMethod() { TraceWriteLine("I'm FooMethod"); } }
En este ejemplo, utilizamos los atributos CallerMemberName para indicar el nombre el método que hace la llamada, CallerFilePath para indicar la ruta del fichero que contiene el método al que llamamos, y CallerLineNumber para indicar el número de línea en la que se realiza la llamada.
Ahora bien, vamos con un truco.
Imaginemos que utilizamos un Framework de .NET diferente del 4.5, por ejemplo .NET Framework 2.0.
El código anterior no funcionaría, ya que los atributos indicados no existen en esa versión de .NET Framework y nos daría un error de compilación.
El siguiente workaround es un apaño directo para solventar este problema.
Bastaría con crear una clase como la que tiene .NET Framework 4.5 ó superior con los atributos que necesitamos, y todo volverá a funcionar.
Por lo tanto, en nuestro proyecto deberíamos crear algo como esto:
namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public class CallerMemberNameAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public class CallerFilePathAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public class CallerLineNumberAttribute : Attribute { } }
Agregando esto a nuestro proyecto .NET Framework 2.0, funcionará tal y como esperamos.
Para más información sobre el namespace System.Runtime.CompilerServices, te sugiero visitar este enlace.
Espero que te sea de tu ayuda.
¡Happy Coding!