Reputation: 1004
I have a .NET winforms application and i am trying to avoid the cumbersome of a debug mode.
As it is the user selects to Enable Debug and by that some operations will take place like writing a log,displaying messages and so on..
I would like to avoid the repeating of
If me.DebugMode then
Write a log
Display A Message on the textBox
.....
There are several / alot of methods that i use and i don't like the idea of polluting the code with the above code
Any recommendations more than welcome
P.S because i have some "complaints" about the "wrong" tag here is the same pseudocode in C# with some extra
if(DebugMode.Checked ==true)
{
Write A log
Display A messagge on the textbox
Dump data as CSV
Activate Tab for Comparing data Before/After
}
Upvotes: 1
Views: 784
Reputation: 15549
I wrote such a thing for WPF and posted on codeproject quite some time ago.
It basically consists of three parts:
ITraceTextSink
) that the TraceListener
uses to send output to the UIThe same concept can easily be applied to WinForms by replacing the UI and binding code.
This allows you to sprinkle Trace.WriteLine like you normally would wherever you want without worrying if "debug" mode is on or not. "Debug" mode consists of attaching the TraceListener
and displaying the UI.
If you poke around the code in the linked codeproject example it should make some sense.
The part that would work without change in WinForms is the TraceListener which looks like this (you'd have to implement an ITraceTextSink
to proxy the message to a Winforms UI component. This is done with a FlowDocument
in this WPF version but text could be pumped into a RichTextBox control as it arrives pretty easily).
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");
}
}
Once you implement the ITraceTextSource
turning on "debug" entails adding it to the collection of trace listeners.
Trace.Listeners.Add(new TraceTextSource(new YourTraceSink()));
Upvotes: 0
Reputation: 117029
Here's an approach.
Let's say I have this code:
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;
}
}
When I run this I get:
4.5 miles is 7.2 kilometres
I can use a dependency injection library to allow me to create an instance of an interface.
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;
}
}
When I run this I get:
4.5 miles is 7.2 kilometres
Now I can introduce a logging decorator:
public class DistanceConversionLoggingDecorator
: Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{
public double MilesToKilometres(double miles)
{
Console.WriteLine("CONVERTING " + miles);
return this.Inner.MilesToKilometres(miles);
}
}
And imply put one line in the configuration section:
injectivity.SetDecorator<IDistanceConversion, DistanceConversionLoggingDecorator>();
When I run this I get:
CONVERTING 4.5 4.5 miles is 7.2 kilometres
So, without changing my code I can inject logging into my code at config.
I can also go ahead and apply attributes to my classes:
[Injectivity.Attributes.Decorator(typeof(IDistanceConversion))]
public class DistanceConversionLoggingDecorator
: Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{ ... }
[Injectivity.Attributes.Factory(typeof(IDistanceConversion))]
public class DistanceConversion : IDistanceConversion
{ ... }
Now instead of using my SetFactory
and SetDecorator
methods I can use this instead:
injectivity.Register(this.GetType().Assembly);
Finally, if I wish I can avoid attributes and define an XML file for configuration, then I just do this:
var injectivity = Injectivity.Context.LoadRoot("config.xml");
Now simply by changing my config file I can turn on or turn off logging without changing my code and with cluttering it with loads of if
statements and logging commands.
Upvotes: 1
Reputation: 675
You could use a logging framework like log4net with properly planed invocation of different logging levels like debug, info, warning, error or fatal.
You then manage activation and deactivation of logging either generally or fine grainer with restriction to minimal level and target (console, file, eventlog, database etc.).
In general a proper logging should be an obligatory part of the source code.
Upvotes: 0
Reputation: 65
Read about postsharp https://www.postsharp.net/diagnostics/net-logging It's the more elegant way that I can imagine
Upvotes: 0
Reputation: 52210
You could write a helper class that takes a flag and a delegate to be executed only if the flag is true. In this example, the delegate also returns a string which is added to the written to the console output (it could just as easily write to a log file).
static class DebugLog
{
static public void Write(bool flag, Func<string> f)
{
if (flag) Console.WriteLine(f);
}
}
You would call it like this:
DebugLog.Write(this.DebugMode, () => "This is a string I wish to log");
If you want to include some additional processing, you can enclose the delegate body in {} and add additional statements:
DebugLog.Write(this.DebugMode, () => {
this.DisplayMessage("You're debugging!");
return "This is a string I wish to log");
});
P.S. You used me
in your example but you tagged this post c#
, so my example is in c#.
If the debug flag is part of global state, you can simplify the individual calls.
static class DebugLog
{
static public bool DebugMode = true;
static public void Write(Func<string> f)
{
if (DebugMode) Console.WriteLine(f);
}
}
which makes it simpler to call, like this:
DebugLog.Write(() => "This is a string I wish to log");
Upvotes: 0
Reputation: 189
Create a class derived from the Form class and implement the desired behaviour in that. Then derive all your forms from this new class.
Upvotes: 0