我有一个.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
}
答案 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
{ ... }
现在我可以使用我的SetFactory
和SetDecorator
方法,而不是使用我的方法:
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写了这样的东西。
它基本上由三部分组成:
ITraceTextSink
用于将输出发送到用户界面的活页夹(TraceListener
)通过替换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