2010-04-14 1 views
4

Я написал простой класс для отладки и я называю метод Debugger.WriteLine (...) в своем коде, как это:Вопрос об эффективных лесозаготовках в C#

Debugger.WriteLine("[Draw]", "InProgress", 
    "[x,y] = " + x.ToString("0.00") + 
    ", " + y.ToString("0.00") + 
    "; pos = " + lastPosX.ToString() + "x" + 
    lastPosY.ToString() + " -> " + posX.ToString() + 
    "x" + posY.ToString() + "; SS = " + 
    squareSize.ToString() + "; MST = " + 
    startTime.ToString("0.000") + "; Time = " + time.ToString() + 
    phase.ToString(".0000") + "; progress = " + 
    progress.ToString("0.000") + "; step = " + 
    step.ToString() + "; TimeMovementEnd = " + 
    UI.MovementEndTime.ToString() 
); 

Тело процедуры Debugger .WriteLine скомпилируется только в режиме отладки (директивы #if, #endif). Меня беспокоит то, что мне часто требуется ToString() в вызове Debugger.WriteLine, что дорого, потому что он создает все еще новые строки (например, для изменения числа). Как решить эту проблему?

Несколько точек/вопросы отладки/трассировки:

  • Я не хочу, чтобы обернуть каждый Debugger.WriteLine в операторе IF или использовать директивы препроцессора для того, чтобы оставить из методов отладки, потому что это неизбежно приведет к не очень читаемому коду и потребует слишком большого набора текста.

  • Я не хочу использовать какие-либо рамки для трассировки/отладки. Я хочу попытаться запрограммировать его сам.

  • Оставляют ли Trace methods при компиляции в режиме деблокирования? Если это возможно, мои методы будут вести себя одинаково?

  • С static String.Format method я могу это сделать:

    выходом = String.Format ("Вы теперь {0} года.", Года);

Что кажется приятным. Является ли это решением для моей проблемы с ToString()?

+0

Есть ли проблема с производительностью в этом методе? – harpo

+0

@harpo: Создано множество неизменяемых строк. Один вызов не так уж плох, но если этот метод выводится достаточно часто, произойдет замедление из-за всех распределений объектов строки. –

+0

Это называется часто. –

ответ

3

Используйте StringBuilder, чтобы создать свои выходные строки, а не объединять каждое значение.

И вы можете создать собственный собственный класс отладчика (MyDbg), который содержит элемент WriteLine, содержимое которого вы можете окружать с помощью директив компиляции. Он не будет полностью компилировать код отладки, но превратит ваши вызовы MyDbg.WriteLine в no-ops.

Вот быстрый эскиз класса:

using System; 
using System.Text ; 

public static class MyDbg 
{ 
    public static void WriteLine(string str) // and some other params 
    { 
     #if DEBUG 

     StringBuilder sb = new StringBuilder(); 
     sb.Append(str); 
     // etc. appending other params as you see fit 
     #endif 
    } 
} 

ИЛИ

[Conditional("DEBUG")] 
public static class MyDbg 
{ 
    public static void WriteLine(string str) // and some other params 
    { 
     StringBuilder sb = new StringBuilder(); 
     sb.Append(str); 
     // etc. appending other params as you see fit 
    } 
} 

Вы хотите изменить его в соответствии со своими потребностями, конечно. И вместо создания отдельного класса вы можете создать метод-член, если #if DEBUG/# endif встроенный для отображения своего собственного состояния, когда в отладчике.

+1

Я не считаю, что StringBuilder будет иметь какое-то значение в этом случае. Поскольку строки собраны в одном выражении, компилятор не будет создавать промежуточные строки для каждой конкатенации. (AFAIK) – harpo

+0

@harpo: Это оптимизация компилятора, о которой я никогда не слышал. Насколько я знаю, строковые операции неизменяемы, и любая конкатенация или увеличение создает новый, независимо от того, где он используется. –

+0

harpo is right: компилятор заменяет символ + b + c строкой. Concat (a, b, c) –

0
  1. Вам не нужно обертывать каждую линию. Просто напишите вспомогательный метод, содержащий Debug.WriteLine и включите/выключите его по флагом (обычно bool).

  2. Отслеживание будет в вашем коде даже в режиме деблокирования. Вы можете настроить его, см. http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx

  3. string.Format вызывает ToString() по внутренним аргументам, поэтому нет никакой пользы.

+0

1. Я сделал это. 2., 3. спасибо за ответ! –

+0

Что касается (3), я думаю, что здесь это не актуально, так как соображения производительности обычно не являются проблемой в конфигурации отладки, так или иначе. 'string.Format' по-прежнему имеет преимущество в улучшении четкости кода (что, я бы сказал, вроде бы идет рука об руку с отладкой.) – stakx

+0

stakx: Я думаю, что это актуально, потому что вы можете включить трассировку в коде выпуска, что влияет на производительность приложений. –

2

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

НТН

1

string.Format() Используя ожидаемый выход на самом деле станет более легко узнаваемы просто глядя на код (ИМХО):

Debug.WriteLine(string.Format(
    "[Draw]InProgress[x,y] = {0:0.00}, {1:0.00}; pos = {2}x{3} -> {4}x{5}; ...", 
    x, y, 
    lastPosX, lastPosY, 
    posX, posY, 
    ...)); 
+0

Спасибо, это хорошо! –

4

Использование отражателя я узнал, что Debug.WriteLine объявлен этот путь:

[Conditional("DEBUG")] 
public static void WriteLine(string message) 

Это означает, что в режиме деблокирования все вызовы этого метода исключаются из кода.

Например, этот код:

public static void Test(int a) 
{ 
    string b = Console.ReadLine(); 
    Debug.WriteLine(a + " " + b); 
    Console.WriteLine(a + " " + b); 
} 

компилируется в режиме выпуска для:

public static void Test(int a) 
{ 
    Console.WriteLine(a + " " + Console.ReadLine()); 
} 
+0

+1; http://msdn.microsoft.com/en-us/library/aa288458(VS.71).aspx - ссылка, которая подтверждает то, что вы сказали. –

1

Узор я использую, чтобы определить интерфейс протоколирования (ILogger), который получает зависимость впрыскивается во все классы

public class MyClassThatLogs 
{ 
    public MyClassThatLogs(ILogger logger) 
    { 
     try 
     { 
      logger.Write("bla bla bla"); 
     } 
     catch(Exception ex) 
     { 
      logger.Write(ex); //overload of Write() that takes in an Exception 
     } 
    } 
} 

Так что, когда вы новичок, вы можете пройти в «реальном» регистраторе или ложном/поддельном

var mc = new MyClassThatLogs(new FakeLogger()); 

Теперь вы отвлекли необходимость знать в классе MyClassThatLogs, что происходит с протоколированием. Базовый SOLID материал. Таким образом, «верхний» (например, метод main() консоли) должен иметь директиву IF DEBUG, а затем передать правильную реализацию регистратора.

+0

Благодарим за предложение! Я думал о [Условный («FakeLogger»)], [Условный («MyLogger»)], ... для классов. Возможно, он будет также гибким, как ваше решение. Изменение регистратора было бы вопросом изменения режима в Visual Studio. –

+0

Прохладный! Важное увлечение, я думаю, состоит в том, чтобы получить зависимость от вашего класса ... вашему классу не важно, как выполняется ведение журнала, он должен просто объявить, что ему нужно регистрироваться. Опять же, это происходит только из принципов SOLID - инверсии контроля и инжекции зависимостей. –