When Time is of the Essence
I was reading this post today and, while I like the possibility to easily time specific parts of my code, I thought the solution given there was not accounting for a number of scenarios:
- What if we want to call a method that has parameters, or one that has a return value ?
- If an exception occurs in the method that's being timed, the timer breaks.
- The code being timed is limit to a single method. Ofcourse, we can always refactor our code in this direction, but still.
- Switching from a method call to passing method call as a delegate seems to change the semantics of the code. This might be a personal thing though.
I've used a similar solution in a number of my projects, which is based on a ctor/dispose-construct. Using it is as simple as placing a 'using'-construct around the code that you want to time:
using (new PerformanceTimer("Running MySlowMethod and MyOtherSlowMethod with parameters"))
{
MySlowMethod(X);
MyOtherSlowMethod(Y);
}
Running this will result in output being printed to the Log console telling us how long it took to execute the code. The code for the PerformanceTimer class is relatively simple:
public class PerformanceTimer : IDisposable
{
private DateTime _start;
private string _caption;
public PerformanceTimer(string caption)
{
_caption = caption;
_start = DateTime.Now;
}
public void Dispose() {
Log.Info("{0}: {1}ms.", _caption, Passed.TotalMilliseconds);
}
public TimeSpan Passed { get { return DateTime.Now - _start; } }
}
What I'm currently interested in is a way of storing these timing results in a database without influencing the performance of the application itself. That way I am able to easily collect live performance data over longer periods of time.
Posted by Filip at 15:05. 5 comments.About Serialization and Events
Recently I was writing a plugin system for a personal project of mine. The plugins ran in a seperate AppDomain, and thus communication between the application and the plugins would have to happen using serializable objects.
I ran into problems with this scenario. Whenever an object of the User type was passed between AppDomains, the framework threw a TypeException saying that another type, UserList, was not serializable. Now, it was not lying - I wasn't planning for the class to be passed between AppDomains, but why was the framework complaining about this class?
Normally, this type of exception means an object your trying to serialize is composed of one or more other classes that aren't serializable. I double-checked the fields and properties exposed by the User class. However, I saw no mention of a reference to the UserList class. I spent quite a while looking for a clue, and it took me quite a while before I realised a UserList object was subscribing to an event exposed on a User object. Turns out that when serializing an object for being passed between AppDomains, subscribers to its events are also being serialized and passed along. Marking the event with a NonSerialized attribute tells the framework not to do this, and hence fixed my problem.
It looks somewhat obvious once you know what's going on, but I guess I was thrown off by the fact that this behavior does not apply to XML serialization (eg. when passing objects to a web service).
Posted by Filip at 18:20. 1 comment.When MaskedTextBox.SelectAll doesn't Select All...
A client recently asked for a seemingly easy feature to be added to an application of his. The application consists of a form with a number of MaskedTextBox objects, and those textboxes are supposed to select their contents once focused, so any keypress after giving focus would overwrite the existing text in the textbox.
Shouldn't be hard, right? Just subscribe to the textbox.Enter event and then call textbox.SelectAll(), that's what, five minutes? An hour later, things still weren't working as they should. For some reason, the SelectAll() call didn't work. It just didn't select anything (although at one point I was able to make it select only a part of the contents, but that was, well, quite useless for my client).
Turns out MaskedTextBox is an eager little sport. If a mask is set, the control does some selecting of its own when it gets focused, and thus it overrides anything you try to do yourself in response to these events. Cute, but annoying. Once I realised that, the solution wasn't too far away: I had to postpone the SelectAll() call so it executes after the focus events have been handled by MaskedTextBox.
Thankfully, Windows Forms provides a BeginInvoke method that will do just that: Control.BeginInvoke will post a Win32 message (you know, WM_*) to the message queue. This message won't be picked up until the focus events have been processed, so we can leverage this to postpone our SelectAll() call.
Doing this is pretty easy using MethodInvoker and anonymous delegates in .NET 2.0:
this.BeginInvoke(new MethodInvoker(delegate { textbox.SelectAll(); }));
If only they would have mentioned this in the documentation. You know, the thing you read to find out about stuff like that :)
Posted by Filip at 11:30. 2 comments.