Регистрация входа и выхода методов вместе с параметрами автоматически? - PullRequest
9 голосов
/ 05 октября 2008

Есть ли способ добавить запись в журнал, чтобы входящие и выходящие методы автоматически каким-либо образом регистрировались вместе с параметрами для целей трассировки? Как бы я это сделал?

Я использую Log4Net.

Ответы [ 7 ]

7 голосов
/ 05 октября 2008

Лучший способ добиться такого рода вещей - использовать перехват. Есть несколько способов сделать это, хотя все они имеют тенденцию быть несколько агрессивными. Можно было бы извлечь все ваши объекты из ContextBoundObject. Здесь - пример использования такого подхода. Другой подход заключается в использовании одной из существующих библиотек АОП для достижения этой цели. Что-то вроде DynamicProxy из Castle Project лежит в основе многих из них. Вот несколько ссылок: Spring.Net PostSharp Cecil

Возможно, есть еще несколько, и я знаю, что Castle Windsor и Ninject оба предоставляют возможности AOP в дополнение к функциональности IoC.

Как только AOP будет установлен, вы просто напишите класс-перехватчик, который будет записывать информацию о вызовах метода в log4net.

На самом деле я не удивлюсь, если одна из платформ AOP предоставит вам такую ​​функциональность из коробки.

4 голосов
/ 05 октября 2008

Я не уверен, каковы ваши реальные потребности, но вот вариант с низкой арендной платой. Это не совсем «автоматически», но вы можете использовать StackTrace для очистки информации, которую вы ищете, таким образом, чтобы не требовать передачи аргументов - аналогично предложению ckramer относительно перехвата:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace TracingSample
{
    class Program
    {
        static void Main(string[] args)
        {
            DoSomething();
        }

        static void DoSomething()
        {
            LogEnter();

            Console.WriteLine("Executing DoSomething");

            LogExit();
        }

        static void LogEnter()
        {
            StackTrace trace = new StackTrace();
            if (trace.FrameCount > 1)
            {
                string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
                string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
                Console.WriteLine("Entering {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
            }
        }

        static void LogExit()
        {
            StackTrace trace = new StackTrace();
            if (trace.FrameCount > 1)
            {
                string ns = trace.GetFrame(1).GetMethod().DeclaringType.Namespace;
                string typeName = trace.GetFrame(1).GetMethod().DeclaringType.Name;
                Console.WriteLine("Exiting {0}.{1}.{2}", ns, typeName, trace.GetFrame(1).GetMethod().Name);
            }
        }
    }
}

Вы можете объединить что-то вроде приведенного выше примера с наследованием, используя не виртуальный открытый член в базовом типе для обозначения метода действия, а затем вызвать виртуального члена для фактического выполнения работы:

public abstract class BaseType
{
    public void SomeFunction()
    {

        LogEnter();
        DoSomeFunction();
        LogExit();
    }

    public abstract void DoSomeFunction();
}

public class SubType : BaseType
{
    public override void DoSomeFunction()
    {
        // Implementation of SomeFunction logic here...
    }
}

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

Надеюсь, это поможет.

4 голосов
/ 05 октября 2008

Посмотрите на:

Как перехватить вызов метода в C #? PostSharp - иль ткачество - мысли

Также выполните поиск SO для AOP или Aspect-Oriented Programming и PostSharp ... вы получите интересные результаты.

3 голосов
/ 05 октября 2008

Вы можете использовать посткомпилятор, например Postsharp . Пример с сайта говорит о настройке трассировщика для входа / выхода из метода, который очень похож на то, что вы хотите.

0 голосов
/ 14 января 2016

Функции

Чтобы расширить ответ Джареда, избегая повторения кода и включая опции для аргументов :

private static void LogEnterExit(bool isEnter = true, params object[] args)
{
    StackTrace trace = new StackTrace(true);  // need `true` for getting file and line info
    if (trace.FrameCount > 2)
    {
        string ns = trace.GetFrame(2).GetMethod().DeclaringType.Namespace;
        string typeName = trace.GetFrame(2).GetMethod().DeclaringType.Name;
        string args_string = args.Length == 0 ? "" : "\narguments: [" + args.Aggregate((current, next) => string.Format("{0},{1};", current, next))+"]";
        Console.WriteLine("{0} {1}.{2}.{3}{4}", isEnter ? "Entering" : "Exiting", ns, typeName, trace.GetFrame(2).GetMethod().Name, args_string );
    }
}

static void LogEnter(params object[] args)
{
    LogEnterExit(true, args);
}

static void LogExit(params object[] args)
{
    LogEnterExit(false, args);
}

Использование

static void DoSomething(string arg1)
{
    LogEnter(arg1);
    Console.WriteLine("Executing DoSomething");
    LogExit();
}

выход

В консоли это будет вывод, если DoSomething запускается с "бла" как arg1

Entering Program.DoSomething
arguments: [blah]
Executing DoSomething
Exiting Program.DoSomething
0 голосов
/ 11 декабря 2012

Вы можете использовать инфраструктуру с открытым исходным кодом CInject в CodePlex, у которого есть LogInjector, чтобы отметить вход и выход вызова метода.

Или вы можете выполнить шаги, упомянутые в этой статье на Перехват вызовов методов с использованием IL и создать свой собственный перехватчик с использованием классов Reflection.Emit в C #.

0 голосов
/ 05 октября 2008

Шаблон Декоратор может помочь.

...