Какой самый эффективный способ записать имя класса и метода? - PullRequest
9 голосов
/ 28 августа 2009

Я в основном хочу написать регистратор / трассировщик клиента, который также регистрирует класс и имя метода, вызывающего регистратор / трассировщик. Это должно быть быстрым, чтобы оно не влияло на производительность приложения, строго типизировано и чисто. У кого-нибудь есть хорошие идеи?

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

  • StackTrace / StackFrame (слишком много накладных расходов?)

  • MethodInfo.GetCurrentMethod () (все еще слишком медленно? И не очень чисто)

  • передать метод в качестве делегата (C # может сделать это неявно, и у меня есть доступ к MethodInfo, но не очень чисто)

Я ценю чьи-либо комментарии.

UPDATE:

Мне понравилась чистота StackFrame, поэтому я задал более конкретный вопрос здесь относительно производительности StackFrame, и я получил несколько действительно хороших ответов, включая тесты производительности. Оказывается, что MethodInfo.GetCurrentMethod() является самым быстрым (занимает около 1 микросекунды на моем компьютере) и new StackFrame(1) может быть запрошено по требованию (занимает около 15-20 микросекунд на моем компьютере). Я выбросил метод в качестве опции делегата, поскольку он слишком запутан, когда метод имеет несколько параметров.

ВЫВОД:

Я рассмотрел все параметры, и лучше всего написать собственный плагин для PostSharp, который вводит имя метода в виде строки в MSIL во время компиляции при применении к нему пользовательского атрибута, например [Trace]. На мой взгляд, это самый быстрый и самый приемлемый вариант. Это даже позволяет намного больше вещей, таких как передача имен параметров и аргументов без какого-либо отражения, а также автоматическое обнаружение и запись исключений. Это мой связанный вопрос для получения дополнительной информации.

Ответы [ 6 ]

4 голосов
/ 19 февраля 2016

Самый быстрый способ - это сделать во время компиляции, это правда, но наиболее удобный способ сделать это в .NET - использовать CallerMemberName , CallerFilePath другие атрибуты службы компилятора, включенные в .NET 4.5:

public void TraceMethodCall([CallerMemberName]string methodName)
{
}
3 голосов
/ 29 августа 2009

Проще говоря, самый быстрый способ сделать это статически во время компиляции:

public void DoSomething()
{
    TraceCall("DoSomething");
} 

public void TraceCall(string methodName)
{
    if (!tracingEnabled) { return; }
    // Log the call
}

Тогда вопрос, по сути, такой же, как ваш предыдущий вопрос; Каков наилучший способ сделать это в удобной и точной форме? Варианты времени выполнения, которые мы обсуждали ранее, имеют относительно серьезный удар по производительности, но компромисс в том, что их легко реализовать.

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

2 голосов
/ 28 августа 2009

Когда вы уже находитесь внутри метода (или если вы перехватываете метод), я не думаю, что вы можете сделать намного лучше, чем MethodInfo.GetCurrentMethod - который не слишком быстр - если вы хотите остаться, - сейф.

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

В зависимости от нагрузки, уже имеющейся в вашем приложении, это может или не может помочь.

0 голосов
/ 30 августа 2009

Если вас беспокоит скорость, то фактическое сообщение журнала должно быть создано с использованием Event Tracing для Windows . ETW - это высокоскоростная библиотека журналов, реализованная в виде драйвера, доступного как из режима ядра, так и из режима пользователя. Трассировка может быть динамически включена и выключена. Ведение журнала добавляет очень мало накладных расходов в приложение. Я использовал ETW для реализации трассировки в высокопроизводительных серверных приложениях. Проверьте NTrace .

0 голосов
/ 28 августа 2009

Я думаю, Log4PostSharp отлично справится с этой задачей.

0 голосов
/ 28 августа 2009

Лучший способ сделать это во время компиляции: C ++ традиционно использовал для этого символы препроцессора ____FILE____ и ____LINE____ в макросах. К сожалению, на данный момент компилятор C # не предлагает макросы или эквивалент ____FILE____ и ____LINE____.

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

...