2008-09-25 8 views
20

Una gran parte de mi código C# sigue este patrón:registro genérico de parámetros de la función de gestión de excepciones

void foo(string param1, string param2, string param3) 
{ 
    try 
    { 
     // do something... 
    } 
    catch(Exception ex) 
    { 
     LogError(String.Format("Error in foo(param1={0}, param2={1}, param3={2}), exception={3}", param1, param2, param3, ex.Message)); 
    } 
} 

¿Hay una manera de .NET para obtener una lista de clave/valor de los parámetros de una función para que ¿Puedo llamar a otra función para construir mi cadena de registro de errores? O ¿Tiene una manera más genérica/mejor de hacer esto?

+0

podría ser algo con Reflexión en el idioma que podría ayudar? – nlucaroni

+0

Puede hacerlo a través de la reflexión, pero se vuelve costoso en el transcurso de muchas llamadas a funciones. –

+3

No creo que pueda hacer esto con Reflection o StackTrace/StackFrame. Creo que su única opción puede ser usar un AOP o marco de postprocesamiento, como PostSharp. –

Respuesta

24

Usted podría utilizar la reflexión y la convención que debe pasar los parámetros a la LogError con el orden correcto:

private static void MyMethod(string s, int x, int y) 
{ 
    try 
    { 
     throw new NotImplementedException(); 
    } 
    catch (Exception ex) 
    { 
     LogError(MethodBase.GetCurrentMethod(), ex, s, x, y); 
    } 
} 

private static void LogError(MethodBase method, Exception ex, params object[] values) 
{ 
    ParameterInfo[] parms = method.GetParameters(); 
    object[] namevalues = new object[2 * parms.Length]; 

    string msg = "Error in " + method.Name + "("; 
    for (int i = 0, j = 0; i < parms.Length; i++, j += 2) 
    { 
     msg += "{" + j + "}={" + (j + 1) + "}, "; 
     namevalues[j] = parms[i].Name; 
     if (i < values.Length) namevalues[j + 1] = values[i]; 
    } 
    msg += "exception=" + ex.Message + ")"; 
    Console.WriteLine(string.Format(msg, namevalues)); 
} 
+0

Bueno. ¿Cómo manejar el objeto? como persona o usuario. –

1

Cuando he hecho esto, acabo de crear un diccionario genérico para el registro.

Tengo esta clase LogArgs. Y al iniciar sesión en una clase base a la que llamo cuando tengo una excepción.

public class LogArgs 
{ 

    public string MethodName { get; set; } 
    public string ClassName { get; set; } 
    public Dictionary<string, object> Paramters { get; set; } 


    public LogArgs() 
    { 
     this.Paramters = new Dictionary<string, object>(); 
    } 

} 

Luego, al comienzo de cada método que hago

LogArgs args = new LogArgs { ClassName = "ClassName", MethodName = "MethodName" }; 
args.Paramters.Add("Param1", param1); 
args.Paramters.Add("Param2", param2); 
args.Paramters.Add("Param3", param3); 

base.Logger.MethodStartLog(args); 

Cuando tengo un error de E conectarse de esta manera.

base.Logger.LogError(args, ex); 
+4

Es un pensamiento interesante, pero cuando te escuches decir "al comienzo de cada método que hago X", considera usar un marco AOP (como PostSharp, como lo sugirieron otros usuarios). – Abel

5

No, no hay una forma de hacerlo.

La práctica habitual es no detectar excepciones a menos que pueda manejarlas.

I.e. normalmente solo detectaría excepciones y las registraría en un manejador de excepciones de nivel superior. A continuación, obtendrá un seguimiento de pila, pero por supuesto no obtendrá detalles de todos los parámetros de todas las llamadas a métodos en la pila.

Obviamente, cuando se depuran, se desean tantos detalles como sea posible. Otras formas de lograr esto son:

  • Use declaraciones Debug.Assert liberalmente para probar las suposiciones que está realizando.

  • Instrumente su aplicación con el registro que se puede activar selectivamente. Uso Log4Net, pero también hay otras alternativas, incluida la utilización de la clase System.Diagnostics.Trace.

En cualquier caso, si no capturar las excepciones sólo a ellos log (me gustaría hacer esto en un límite de nivel en una aplicación de n niveles, por lo que las excepciones se registran en el servidor), entonces debería siempre volver a lanzar ellos:

try 
{ 
    ... 
} 
catch(Exception ex) 
{ 
    log(ex); 
    throw; 
} 
+0

Esto desenrolla la pila, lo que significa que la pila de llamadas differenc se registrará y se volverá a generar. Para evitar esto, ahora es posible tomar ventaja de los filtros de excepción: 'tratar { // ...} catch (Exception ex) cuando (log (ex)) {// nunca entró } ' donde la función' log' siempre devuelve 'false'. – ensisNoctis

1

Se puede usar un estilo similar de construir el mensaje, además de añadir la palabra clave params en su método LogError para manejar los argumentos. Por ejemplo:

public void LogError(string message, params object[] parameters) 
    { 
     if (parameters.Length > 0) 
      LogError(string.Format(message, parameters)); 
     else 
      LogError(message); 
    } 
6

usted podría utilizar la programación orientada a aspectos con PostSharp (echar un vistazo en http://www.postsharp.org, y el tutorial en http://www.codeproject.com/KB/cs/ps-custom-attributes-1.aspx).Básicamente se podría hacer algo como esto:

public class LogExceptionAttribute : OnExceptionAspect 
{ 
public override void OnException(MethodExecutionEventArgs eventArgs) 
{ 
    log.error("Exception occurred in method {0}", eventArgs); 
} 
} 

[LoggingOnExceptionAspect] 
public foo(int number, string word, Person customer) 
{ 
    // ... something here throws an exception 
} 

Tal vez no es lo que quieren, pero estoy seguro de que se puede adaptar para satisfacer sus necesidades.

+0

Relacionados: [¿Qué es la programación orientada a aspectos?] (Http://stackoverflow.com/q/242177/1497596) – DavidRR

+0

postsharp.org ya no existe – Craig

-2

hay escenarios de algunos parámetros o gran número de parámetros ...

  1. pocos parámetros, sin más, mejor escribir como parte del mensaje de registro/excepción.

  2. En grandes parámetros, una aplicación de varias capas estaría utilizando ENTITIES (como cliente, CustomerOrder ...) para transferir datos entre capas. Estas entidades deben aplicar ToString anulación() de la clase Object, no por,

Mensaje de registro ("método comenzó" + paramObj.ToString()) daría a la lista de los datos en el objeto .. Cualquier opiniones? :)

gracias

0

Ésta es pequeño post anticuado, pero por si acaso alguien viene a través de este como lo hice yo - yo resolvió este problema utilizando PostSharp.

Aunque no es prácticamente gratis. La licencia Express (descargable a través de NuGet en VS) le permite decorar su método con el atributo [Log] y luego elegir su mecanismo ya configurado para el registro, como log4netnLog etc. Ahora comenzará a ver entradas de nivel de depuración en su registro dando detalles del parámetro.

Con licencia expresa, solo pude decorar un máximo de 50 métodos en mi proyecto. Si se adapta a tus necesidades, ¡ya estás listo!

Cuestiones relacionadas