如何为我的应用程序实现优雅的调试模式

时间:2017-02-28 21:12:14

标签: c# .net vb.net winforms

我有一个.NET winforms应用程序,我试图避免繁琐的调试模式 因为用户选择启用调试,所以会发生一些操作,如写日志,显示消息等等。
我想避免重复

If me.DebugMode then  
    Write a log
    Display A Message on the textBox  
    .....

我使用了几种/很多方法,我不喜欢用上面的代码污染代码的想法
任何建议超过欢迎
P.S因为我对“错误”标签有一些“抱怨”,这与C#中的伪代码有一些额外的

if(DebugMode.Checked ==true)
{
Write A log
Display A messagge on the textbox
Dump data as CSV
Activate Tab for Comparing data Before/After
}

6 个答案:

答案 0 :(得分:1)

这是一种方法。

假设我有这段代码:

void Main()
{
    var dc = new DistanceConversion();
    var miles = 4.5;
    Console.WriteLine("{0} miles is {1} kilometres", miles, dc.MilesToKilometres(miles));
}

public class DistanceConversion
{
    public double MilesToKilometres(double miles)
    {
        return miles * 8.0 / 5.0;
    }
}

当我跑步时,我得到:

4.5 miles is 7.2 kilometres

我可以使用依赖注入库来允许我创建接口的实例。

void Main()
{
    // Somewhere in my configuration
    var injectivity = Injectivity.Context.CreateRoot();
    injectivity.SetFactory<IDistanceConversion, DistanceConversion>();

    // Here's the previous example using dependency injection.
    var dc = injectivity.Resolve<IDistanceConversion>();
    var miles = 4.5;
    Console.WriteLine("{0} miles is {1} kilometres", miles, dc.MilesToKilometres(miles));
}

public interface IDistanceConversion
{
    double MilesToKilometres(double miles);
}

public class DistanceConversion : IDistanceConversion
{
    public double MilesToKilometres(double miles)
    {
        return miles * 8.0 / 5.0;
    }
}

当我跑步时,我得到:

4.5 miles is 7.2 kilometres

现在我可以介绍一个日志装饰器:

public class DistanceConversionLoggingDecorator
    : Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{
    public double MilesToKilometres(double miles)
    {
        Console.WriteLine("CONVERTING " + miles);
        return this.Inner.MilesToKilometres(miles);
    }
}

并暗示在配置部分添加一行:

injectivity.SetDecorator<IDistanceConversion, DistanceConversionLoggingDecorator>();

当我跑步时,我得到:

CONVERTING 4.5
4.5 miles is 7.2 kilometres

因此,在不更改我的代码的情况下,我可以在config中注入我的代码。

我也可以继续将属性应用到我的课程中:

[Injectivity.Attributes.Decorator(typeof(IDistanceConversion))]
public class DistanceConversionLoggingDecorator
    : Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{ ... }

[Injectivity.Attributes.Factory(typeof(IDistanceConversion))]
public class DistanceConversion : IDistanceConversion
{ ... }

现在我可以使用我的SetFactorySetDecorator方法,而不是使用我的方法:

injectivity.Register(this.GetType().Assembly);

最后,如果我希望我可以避免属性并定义XML文件进行配置,那么我就这样做:

var injectivity = Injectivity.Context.LoadRoot("config.xml");

现在只需更改我的配置文件,我就可以打开或关闭日志记录,而无需更改我的代码,并使用if语句和日志记录命令加载它。

答案 1 :(得分:0)

创建一个派生自Form类的类,并在其中实现所需的行为。然后从这个新类派生所有表单。

答案 2 :(得分:0)

您可以编写一个辅助类,只有在标志为true时才会执行标志和委托。在此示例中,委托还返回一个字符串,该字符串被添加到写入控制台输出中(它可以很容易地写入日志文件)。

#define reverse_2byte(b)    ( ((uint16_t)b & 0b0000000000000001) ? 0b1000000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000000010) ? 0b0100000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000000100) ? 0b0010000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000001000) ? 0b0001000000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000010000) ? 0b0000100000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000000100000) ? 0b0000010000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000001000000) ? 0b0000001000000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000010000000) ? 0b0000000100000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000000100000000) ? 0b0000000010000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000001000000000) ? 0b0000000001000000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000010000000000) ? 0b0000000000100000 : 0 ) | \
                            ( ((uint16_t)b & 0b0000100000000000) ? 0b0000000000010000 : 0 ) | \
                            ( ((uint16_t)b & 0b0001000000000000) ? 0b0000000000001000 : 0 ) | \
                            ( ((uint16_t)b & 0b0010000000000000) ? 0b0000000000000100 : 0 ) | \
                            ( ((uint16_t)b & 0b0100000000000000) ? 0b0000000000000010 : 0 ) | \
                            ( ((uint16_t)b & 0b1000000000000000) ? 0b0000000000000001 : 0 ) 

你会这样称呼:

static class DebugLog
{
    static public void Write(bool flag, Func<string> f)
    {
        if (flag) Console.WriteLine(f);
    }
}

如果要包含一些额外的处理,可以将代理主体括在{}中并添加其他语句:

DebugLog.Write(this.DebugMode, () => "This is a string I wish to log");

P.S。您在示例中使用了DebugLog.Write(this.DebugMode, () => { this.DisplayMessage("You're debugging!"); return "This is a string I wish to log"); }); 但是您标记了此帖子me,因此我的示例位于c#中。

如果调试标志是全局状态的一部分,则可以简化单个调用。

c#

这样可以更简单地调用,如下所示:

static class DebugLog
{
    static public bool DebugMode = true;

    static public void Write(Func<string> f)
    {
        if (DebugMode) Console.WriteLine(f);
    }
}

答案 3 :(得分:0)

了解postharp https://www.postsharp.net/diagnostics/net-logging 这是我能想象的更优雅的方式

答案 4 :(得分:0)

您可以使用log4net之类的日志记录框架,并对调试,信息,警告,错误或致命等不同的日志记录级别进行适当的计划调用。
然后,您可以通过限制到最低级别和目标(控制台,文件,事件日志,数据库等)来管理一般或精细记录的日志记录的激活和取消激活。
通常,正确的日志记录应该是源代码的必要部分。

答案 5 :(得分:0)

我很久以前就为WPF和posted on codeproject写了这样的东西。

它基本上由三部分组成:

  1. 继承自路由跟踪消息的TraceListener的类 到UI组件
  2. 侦听跟踪输出并显示
  3. 的UI组件
  4. ITraceTextSink用于将输出发送到用户界面的活页夹(TraceListener
  5. 通过替换UI和绑定代码,可以轻松地将相同的概念应用于WinForms。

    这使您可以像往常一样在任何地方撒上Trace.WriteLine,而不必担心&#34;调试&#34;模式是否开启。 &#34;调试和#34;模式包括附加TraceListener并显示用户界面。

    如果您在链接的代码项目示例中查看代码,那么它应该是有意义的。

    在WinForms中无需更改即可工作的部分是TraceListener,它看起来像这样(您必须实现ITraceTextSink以将消息代理到Winforms UI组件。这是通过{ {1}}在这个WPF版本中,但文本可以很容易地输入到RichTextBox控件中。

    FlowDocument

    实施sealed class TraceTextSource : TraceListener { public ITraceTextSink Sink { get; private set; } private bool _fail; private TraceEventType _eventType = TraceEventType.Information; public TraceTextSource(ITraceTextSink sink) { Debug.Assert(sink != null); Sink = sink; } public override void Fail(string message) { _fail = true; base.Fail(message); } public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) { _eventType = eventType; base.TraceEvent(eventCache, source, eventType, id, message); } public override void Write(string message) { if (IndentLevel > 0) message = message.PadLeft(IndentLevel + message.Length, '\t'); if (_fail) Sink.Fail(message); else Sink.Event(message, _eventType); _fail = false; _eventType = TraceEventType.Information; } public override void WriteLine(string message) { Write(message + "\n"); } } 开启&#34;调试&#34;需要将它添加到跟踪侦听器的集合中。

    ITraceTextSource