c# - vectores - ¿Hay alguna manera de obtener una matriz de argumentos pasados a un método?
metodos con arreglos en c# (9)
Digamos que tengo un método:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
object[] args = GetArguments();
LogParamaters(args);
#endif
// Do Normal stuff in the method
}
¿Hay alguna forma de recuperar una matriz de argumentos pasados al método para que puedan registrarse?
Tengo una gran cantidad de métodos y quiero evitar pasar manualmente los argumentos por nombre al registrador, ya que el error humano inevitablemente se infiltrará.
Supongo que implicará la reflexión de alguna forma, lo cual está bien, ya que solo se usará para la depuración.
Actualizar
Un poco más de información:
No puedo cambiar la firma del método de SomeMethod, ya que está expuesto como un WebMethod y tiene que replicar el sistema heredado al que imita.
El sistema heredado ya registra los argumentos que se transfieren. Para comenzar con la nueva implementación, se ajustará el sistema heredado, por lo que estoy buscando registrar los parámetros que vienen en la versión C #, de modo que pueda verificar que se pasen los parámetros correctos. en el orden correcto.
Solo estoy buscando registrar los valores y el orden de los argumentos, no sus nombres.
Bueno, si solo quieres pasar los valores, puedes hacer trampa y definir una matriz de objetos:
public static void LogParameters(params object[] vals)
{
}
Sin embargo, esto generará boxeo en los tipos de valores y no le dará ningún nombre de parámetro.
Digamos que tengo un método:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
LogParamaters(p1, p2, p3);
#endif
// Do Normal stuff in the method
}
Actualización: desafortunadamente la reflexión no lo hará todo automáticamente. Tendrá que proporcionar los valores, pero puede usar la reflexión para proporcionar los nombres / tipos de parámetros:
¿Cómo puede obtener los nombres de los parámetros del método?
Entonces el método sig cambiaría a algo así como:
public static void LogParameters(string[] methodNames, params object[] vals)
{ }
Entonces puede hacer cumplir / asumir que cada índice en cada colección cuenta, de modo que methodNames[0]
tiene el valor vals[0]
.
Claro que sí ... echa un vistazo a esta publicación, obtiene los valores reales de los params. cómo enumerar los parámetros del método pasado
Esto es lo que se me ocurrió como una solución:
PostSharp u otra solución de AOP no era realmente práctica en esta situación, así que lamentablemente tuve que abandonar esa idea.
Parece que si bien es posible parametrizar nombres y tipos mediante la reflexión, la única forma de acceder a los valores de tiempo de ejecución es con un depurador adjunto.
Vea aqui para mas informacion:
microsoft.public.dotnet.framework
Así que eso me dejó con el problema de ~ 50 métodos que necesitaban este registro agregando a mano.
Reflexión al rescate ...
public String GetMethodParameterArray()
{
var output = new StringBuilder();
output.AppendLine();
Type t = typeof(API);
foreach (var mi in t.GetMethods())
{
var argsLine = new StringBuilder();
bool isFirst = true;
argsLine.Append("object[] args = {");
var args = mi.GetParameters();
foreach (var pi in args)
{
if (isFirst)
{
isFirst = false;
}
else
{
argsLine.Append(", ");
}
argsLine.AppendFormat("{0}", pi.Name);
}
argsLine.AppendLine("};"); //close object[] initialiser
output.AppendLine(argsLine.ToString());
output.AppendFormat("Log(/"{0}/",args);", mi.Name);
output.AppendLine();
output.AppendLine();
}
return output.ToString();
}
Este fragmento de código recorre los métodos de una clase y genera una matriz de objeto [] inicializada con los argumentos pasados al método y una llamada de registro que contiene los argumentos y el nombre del método.
Ejemplo de salida:
object[] args = {username, password, name, startDate, endDate, cost};
Log("GetAwesomeData",args);
Este bloque se puede pegar en la parte superior del método para lograr el efecto requerido.
Es más manual de lo que me hubiera gustado, pero es mucho mejor que tener que escribir los parámetros a mano y mucho menos propenso a errores.
Hay alguna funcionalidad con el sistema de tipo dinámico que puede hacerlo, pero luego su clase necesita heredar de las clases base dinámicas
Los params pozo ayudan con la llamada de registro, pero no ayudan a las firmas de métodos existentes. El registro usando un marco de AOP podría ser un enfoque más productivo?
Mientras sepa qué tipos esperar, podría registrarlos en una base de datos SQL. Escriba un método que haga una verificación de tipo, y luego rellene la columna DB correspondiente con el valor del parámetro (argumento). Si tiene un tipo personalizado, puede usar el nombre del tipo y guardarlo como una cadena en su propia columna especial.
-Editar
Además, utilizando el método de extensión MethodBase.Name
, puede asociar sus parámetros con el método que los tomó como argumentos como se menciona en otra publicación a continuación. Sea una forma útil de realizar un seguimiento de todos los métodos utilizados, y con qué argumentos, y de qué tipo.
¿Es incluso vagamente una buena idea? :)
No estoy seguro si la API para acceder a la pila de llamadas proporciona un medio para obtener la lista de argumentos.
Sin embargo, hay formas de inyectar IL para interceptar llamadas a métodos y ejecutar código personalizado.
La Biblioteca que uso con frecuencia es PostSharp de Gael Fraiteur, incluye una aplicación que ejecuta postbuild e inyecta IL en los ensamblados de salida, dependiendo de los Aspectos que está utilizando. Existen atributos con los que puede decorar conjuntos, tipos o métodos individuales. Por ejemplo:
[Serializable]
public sealed class LoggingAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs eventArgs)
{
Console.WriteLine("Entering {0} {1} {2}",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
string.Join(", ", eventArgs.Arguments.ToArray()));
eventArgs.MethodExecutionTag = DateTime.Now.Ticks;
}
public override void OnExit(MethodExecutionArgs eventArgs)
{
long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag;
TimeSpan ts = TimeSpan.FromTicks(elapsedTicks);
Console.WriteLine("Leaving {0} {1} after {2}ms",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
ts.TotalMilliseconds);
}
}
Después de esto, puedes decorar el método que quieras con este Atributo:
[Logging]
public void SomeMethod(String p1, String p2, int p3)
{
//..
}
Si usa Postsharp , simplemente puede agregar un atributo al método que desea registrar. Dentro de este atributo puede escribir el código de registro y también proporcionará los argumentos que necesita. Esto se conoce como preocupaciones transversales y AOP (programación orientada a aspectos)
podría no funcionar en algunos escenarios pero debería comenzar :)
class Program
{
static void Main(string[] args)
{
M1("test");
M2("test", "test2");
M3("test", "test2", 1);
Console.ReadKey();
}
static void M1(string p1)
{
Log(MethodBase.GetCurrentMethod());
}
static void M2(string p1, string p2)
{
Log(MethodBase.GetCurrentMethod());
}
static void M3(string p1, string p2, int p3)
{
Log(MethodBase.GetCurrentMethod());
}
static void Log(MethodBase method)
{
Console.WriteLine("Method: {0}", method.Name);
foreach (ParameterInfo param in method.GetParameters())
{
Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name);
}
}
}