Подтвердить что ты не робот

Генерирование регистрации параметров функции при обработке исключений

Многое из моего кода на С# следует этому шаблону:

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));
    }
}

Есть ли способ в .NET, чтобы получить список параметров Key/Value для функции, чтобы я мог вызвать другую функцию для построения строки регистрации ошибок? ИЛИ У вас есть более общий/лучший способ сделать это?

4b9b3361

Ответ 1

Вы можете использовать Reflection и соглашение, что вы должны передать параметры LogError в правильном порядке:

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));
}

Ответ 2

Вы можете использовать аспектно-ориентированное программирование с помощью PostSharp (посмотрите http://www.postsharp.org, а учебник на http://www.codeproject.com/KB/cs/ps-custom-attributes-1.aspx). В основном вы можете сделать что-то вроде этого:

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
}

Возможно, не совсем то, что вы хотите, но я уверен, что он может быть адаптирован в соответствии с вашими потребностями.

Ответ 3

Нет никакого способа сделать это.

Обычная практика заключается в том, чтобы не перехватывать исключения, если вы не можете их обработать.

т.е. вы обычно будете ловить исключения и записывать их в обработчик исключений верхнего уровня. Затем вы получите трассировку стека, но, конечно же, не получите подробную информацию обо всех параметрах всех вызовов методов в стеке.

Очевидно, что при отладке вы хотите как можно больше деталей. Другие способы достижения этого:

  • Используйте операторы Debug.Assert, чтобы анализировать допущения, которые вы делаете.

  • Инструмент приложения с протоколированием, который можно активировать выборочно. Я использую Log4Net, но есть и другие альтернативы, включая использование класса System.Diagnostics.Trace.

В любом случае, если вы перехватываете исключения только для их регистрации (я бы сделал это на границе уровня в приложении n-уровня, чтобы исключения регистрировались на сервере), тогда вы всегда должны их сверять:

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

Ответ 4

Когда я это сделал, я просто создал общий словарь для ведения журнала.

У меня есть этот класс LogArgs. И вход в базовый класс, который я вызываю, когда у меня есть исключение.

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>();
    }

}

Тогда в начале каждого метода я делаю

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);

Когда у меня есть ошибка, я регистрирую ее таким образом.

base.Logger.LogError(args, ex);

Ответ 5

Вы можете использовать похожий стиль построения сообщения, но добавьте ключевое слово params в свой метод LogError для обработки аргументов. Например:

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

Ответ 6

Это небольшая датировка, но на всякий случай кто-то сталкивается с этим, как и я, - я решил эту проблему, используя PostSharp.

Это не практически бесплатно, хотя. Лицензия Express (загружаемая через NuGet в VS) позволяет вам украсить ваш метод атрибутом [Log], а затем выбрать уже настроенный механизм ведения журнала, например log4net nLog и т.д. Теперь вы начнете видеть записи уровня отладки в параметрах вашего журнала.

С помощью экспресс-лицензии я мог только украсить максимум 50 методов в моем проекте. Если это соответствует вашим потребностям, вам хорошо идти!

Ответ 7

Существуют сценарии нескольких параметров или Большое количество параметров...

  • Несколько параметров без особого шума лучше записывать их как часть сообщения о регистрации/исключении.

  • В больших параметрах многоуровневое приложение будет использовать ENTITIES (например, Customer, CustomerOrder...) для передачи данных между слоями. Эти организации должны внедрять переопределить методы ToString() класса Object, там,

Logmessage ( "метод запущен" + paramObj.ToString()) предоставит список данных в объекте. Любые мнения?:)

спасибо