En algunas ocasiones puede resultar interesante averiguar desde qué otro método o métodos se ha llamado a la función actual. las utilidades pueden ser varias, por ejemplo:
- Un método genérico que se use para llamar a procedimientos almacenados en una base de datos, cuyo nombre (el de los procedimientos) sea idéntico al procedimiento desde el que se llama. Puede acelerar mucho el desarrolo.
- Un método que queremos que sea llamado exclusivamente desde otro procedimiento concreto.
- Una función que deba ser llamada en exclusiva desde el constructor de una clase o desde Main().
- Experimentar con esto, que es interesante, hombre... ;-)
En fin, el caso es que con la plataforma .NET casi cualquier cosa es posible y encima de una forma relativamente sencilla. En este caso debemos usar la clase StackTrace del espacio de nombres System.Diagnostics. Ésta nos permite navegar por la pila de llamadas de la aplicaicón obteniendo información sobre los diferentes métodos que se encuentren en ella. Por lo tanto la solución es directa ya que basta con llamar a los métodos correspondientes (GetFrame y GetMethod) para ir obteniendo la información que deseemos. El siguiente código ilustra una función llamada GetCallerName() que nos permite averiguar el nombre de la función desde la que se ha llamado a la actual:
private static string GetCallerName()
{
StackTrace trace = new StackTrace(StackTrace.METHODS_TO_SKIP+2);
StackFrame frame = trace.GetFrame(0);
MethodBase caller = frame.GetMethod();
if( caller == null )
{
throw new InvalidProgramException();
}
return caller.Name;
}
Hay que fijarse en un detalle. En el constructor de la clase StackTrace, al principio, le indicamos que queremos posicionar la información de la traza en dos métodos por encima del actual (constante METHODS_TO_SKIP + 2). Si no lo hiciéramos obtendríamos en primer lugar la información del método actual, es decir, del propio GetCallername. Eso implica saltarse un "frame" de la pila de llamadas. De todos modos hemos de tener encuenta que a esta función la llamamos desde aquella sobre la que queremos saber quién la llamó, por lo que ésta también debemos saltárnosla, de ahí el que le sumemos uno más. para entendelo mejor. Supongamos que escribimos el siguiente código:
private static void Funcion1()
{
Funcion2();
}
private static void Funcion2()
{
Funcion3();
}
private static void Funcion3()
{
Console.Write(GetCallerName());
}
La pila de llamadas sería la siguiente vista desde dentro de nuestra función GetCallerName:
Funcion1 > Funcion2 > Funcion3 > GetCallerName
Es decir, nos tenemos que saltar la función actual y la función desde la que se está llamando yasí obtenemos directamente en el primer elemento dela pila el "frame" de la función que nos interesa. También podíamos haber obviado este salto en el constructor y habernos ido directamente al tercer elemento de la pila de llamadas, pero esta técnica es más eficiente.
Al llamar al método GetFrame de la traza, obtenemos una referencia a un objeto de la clase StackFrame, cuyo método GetMethod nos devuelve una referencia a un objeto de la clase MethodBase. Ésta está en el espacio de nombres System.Reflection y permite obtener toda la información que necesitemos del método que representa. Así que lo único que resta es acceder a sus propiedad, en este caso su nombre (propiedad Name) y listo.
He incluido un archivo de ejemplo en el que se muestra una función similar y otra que permite obtener directametne una volcado de la pila de llamadas en la consola. Está escrito en C# pero es muy fácil de pasar a VB.NET.