C# 关于C中有效登录的问题#

C# 关于C中有效登录的问题#,c#,debugging,trace,C#,Debugging,Trace,我编写了一个用于调试的简单类,并在代码中调用方法Debugger.WriteLine(…),如下所示: Debugger.WriteLine("[Draw]", "InProgress", "[x,y] = " + x.ToString("0.00") + ", " + y.ToString("0.00") + "; pos = " + lastPosX.ToString() + "x" + lastPosY.ToString() + " -> " +

我编写了一个用于调试的简单类,并在代码中调用方法Debugger.WriteLine(…),如下所示:

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)。让我担心的是,我经常需要在Debugger.WriteLine调用中调用String(),这代价很高,因为它会创建新字符串(例如更改数字)。如何解决这个问题

关于调试/跟踪的几点/问题:

  • 我不想将每个Debugger.WriteLine都封装在IF语句中,也不想使用预处理器指令来省去调试方法,因为这将不可避免地导致代码不太可读,并且需要太多的键入

  • 我不想使用任何框架进行跟踪/调试。我想试着自己编程

  • 如果在发布模式下编译,是否会忽略?如果是这样的话,我的方法是否也会有类似的行为

  • 有了这些,我可以做到:

    output=String.Format(“您现在{0}岁。”,岁)

看起来不错。这是我的ToString()问题的解决方案吗?

用于创建输出字符串,而不是串联每个值

您还可以创建自己的自定义调试器(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
    }
}

当然,你会根据自己的需要修改它。如果#if DEBUG/#endif内置用于在调试器中显示其自身状态,则可以创建成员方法,而不是创建单独的类

  • 您不需要包装每一行。只需编写包含Debug.WriteLine的helper方法,并通过标志(通常是bool)将其打开/关闭

  • 即使在发布模式下,跟踪也会出现在代码中。您可以对其进行配置,请参阅

  • Format在内部对参数调用ToString(),因此没有任何好处


  • 对于日志记录,请查看诸如Log4net或企业库之类的框架。它们以多种方式配置日志记录。即使你想登录


    HTH

    使用Reflector,我发现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());
    }
    

    我使用的模式是定义一个日志接口(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类中了解日志记录情况的需要。基本固体材料。因此,“top”(比如控制台的main()方法)将具有IF DEBUG指令,然后传入记录器的正确实现。

    此方法中真的存在性能问题吗?@harpo:创建了许多不可变字符串。一次调用并不太糟糕,但是如果这个方法输出的频率足够高,那么由于所有的字符串对象分配,速度会变慢。我不相信StringBuilder在这种情况下会有什么不同。由于字符串是在单个语句中组装的,编译器不会为每个串联创建中间字符串。(AFAIK)@harpo:这是我从未听说过的编译器优化。据我所知,字符串操作是不可变的,任何连接或扩充都会创建一个新的操作,不管它在哪里使用。harpo是对的:编译器用字符串替换a+b+c。Concat(a,b,c)我的方法的内容被编译指令包围。但如何使用StringBuilder,并且仍然只有一行调试方法调用?@Paul Sasik:使用Reflector,自己看看+1;-确认您所说内容的链接。谢谢您的建议!我在想[有条件的(“FakeLogger”),[有条件的(“MyLogger”),。。。上课。也许它也可以作为您的解决方案。记录器的更改将是VisualStudio中更改模式的问题。酷!我认为最重要的一点是从你的类中去掉依赖性。。。您的类不应该关心日志记录是如何实现的,它应该声明它需要日志记录。同样,这只是来自可靠的原则——控制反转和依赖注入。stakx:我认为这是相关的,因为您可以在发布代码中启用跟踪,从而影响应用程序性能。
    var mc = new MyClassThatLogs(new FakeLogger());