I've been writing up some demos for the Readify Pro .NET 3.5 course over the past couple of days and on a couple of occasions I've run into the situation of needing to time a set of operations. The way I usually approach this is to get the time from DateTime.Now before and after the operations and print the result to the screen. This was starting to become tedious:

long startTime = DateTime.Now.Ticks;
System.Threading.Thread.Sleep(1500);
long endTime = DateTime.Now.Ticks;
Console.WriteLine("Time Elapsed: {0}", new TimeSpan(endTime - startTime).TotalMilliseconds.ToString());

So, I decided to take a different approach. After using RhinoMocks I stumbled upon the MockRepository.Record method. This method can be used to wrap a set of mock statements in a using block. "Eureka!" I shout...

How do I accomplish this, now...? I want to have a StopWatch that has a Time method. I want to call the Time method with a using statement and time the statements that execute within the block. This means my Time method needs to return an object that implements IDisposable so that the Dispose method is hit at the end of the using block.

What shall the Time method return...? How about a Timer object? I know, I'm a creative genious! :)

 
public class Timer : IDisposable
{
    public DateTime StartTime { get; private set; }
    public DateTime EndTime { get; private set; }
    internal event EventHandler<TimerStoppedEventArgs> TimerStopped;

    public void BeginTiming()
    {
        StartTime = DateTime.Now; // Start the timer by recording the current time.
    }

    public void StopTiming()
    {
        EndTime = DateTime.Now; // Record the end time.
        OnTimingStopped(); // Call to raise the TimerStopped event.
    }

    protected virtual void OnTimingStopped()
    {
        TimeSpan span = EndTime - StartTime; // Create the TimeSpan that defines the elapsed time.
        if (TimerStopped != null) // Raise the TimerStopped event.
            TimerStopped(this, new TimerStoppedEventArgs(span));
    }

    public void Dispose()
    {
        if (EndTime == DateTime.MinValue) // We've hit the end of the using block! Stop the timer!
            StopTiming();
    }
}

/// <summary>
/// Describes a TimerStopped event by providing the elapsed time as a TimeSpan.
/// </summary>
internal class TimerStoppedEventArgs : EventArgs
{
    public TimeSpan ElapsedTime { get; set; }
    public TimerStoppedEventArgs(TimeSpan elapsedTime)
    {
        ElapsedTime = elapsedTime;
    }
}

Ok, now to utilise this in the StopWatch...

public class StopWatch
{
    Timer currentTimer; // The Timer currently in use.

    /// <summary>
    /// The total time that the StopWatch timed.
    /// </summary>
    public TimeSpan TotalElapsedTime { get; private set; }

    public Timer Time()
    {
        // Check to see the StopWatch isn't already in use.
        if (currentTimer != null) throw new InvalidOperationException("You are already using this StopWatch!");
        // Create a Timer, create an event handler for it's TimerStopped event, start it and return it.
        currentTimer = new Timer();
        currentTimer.TimerStopped += new EventHandler<TimerStoppedEventArgs>(currentTimer_TimerStopped);
        currentTimer.BeginTiming();
        return currentTimer;
    }

    public TimeSpan GetCurrentElapsedTime()
    {
        // Check to see the StopWatch is in use.
        if (currentTimer == null) throw new InvalidOperationException("You aren't timing anything...");
        return DateTime.Now - currentTimer.StartTime; // Return the current time - the timer's start time.
    }

    void currentTimer_TimerStopped(object sender, TimerStoppedEventArgs e)
    {
        if (e != null) // Set the total elapsed time of the StopWatch.
            TotalElapsedTime = e.ElapsedTime;
        if (currentTimer != null) // Kill the current Timer.
            currentTimer.TimerStopped -= new EventHandler<TimerStoppedEventArgs>(currentTimer_TimerStopped);
        currentTimer = null;
    }
}

That's it! 90 lines of code (including comments) and five minutes later I have a StopWatch. I even threw a GetCurrentElapsedTime method in there for fun too.

Now, to test it out...

StopWatch watch = new StopWatch();
using (watch.Time())
{
    System.Threading.Thread.Sleep(1500);
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

This was actually giving me around 1520ms. Hmm...

So I went back to my old method to test this out, and found that the following code ran with the same results... Excellent!

Ok, so using the DateTime.Now compare method isn't exactly going to be good for real time computing but, for demos and the like I think it will do the job. And it definitely makes the code look that little bit neater.

I've got a little sample available in my downloads for those interested.

Technorati Tags: ,

This week I've got the "luxury" of working from home. After my last 1-2 week stint of this back in March, I've decided to tackle things a little differently.

Firstly, I'm not breaking my routine! I've been going to the gym every morning for the past 7 weeks. It's really helped me feel better about myself. Last time I was working from home, I decided to give the gym a break for a little. What happened next was that I stopped going all together for about 3 months. So, breaking my routine is not going to happen this week.

Secondly, have a five minute break every hour. This is something that really got lost for me last time. I ended up sitting in my chair for 6 hours straight every day, not having anything to eat and relying on a bottle of water to keep me going. This is very bad behaviour and will really affect me now that I'm not changing my gym routine. Taking a quick walk around the house for five minutes every hour and ensuring I get some food into me every 2 hours is goal I will be actively pursuing.

Lastly, switch off the computer at 6PM every night, even if it doesn't stay off all night. This essentially reboots my brain. :)

So, what will I be doing this week...? Today I'm doing some more PD around the ASP.NET MVC. Hopefully I'll get some time to hit Silverlight 2, but at this stage it's not looking likely. Tomorrow I'll be doing some work on developing our new Professional .NET Course.

I'll try to keep active on my blog and I'll be twittering away as much as possible.

I'm famous: http://blogs.technet.com/itproaustralia/archive/2008/03/06/technet-vodcast-of-the-sydney-heroes-happen-2008-event.aspx

Watch out for the good looking guy at the end... :-p

I had a great time the other day at the launch event. It was great getting a chance to check out the new improvements in VS, SQL and Windows 2008. And I had a blast catching up with the DPE guys. The free copy of Vista and Windows Server will definitely not go to waste.

BTW, thanks for putting me on the spot Deeps... ;-)

Technorati Tags:

I managed to download and install IE8 today, after hearing it was available from the Microsoft web site.

The overall setup experience was quite painless, and it managed to keep all my settings from IE7.

The first page that loads after installing introduces the new features of IE8 - i.e. Activities, WebSlices and IE7 Emulation.

Activities

Activities give users ready access to the online services they care about most from any page they visit, and developers gain an easy way to extend the reach of their online services. It’s as simple as selecting text to get started with an Activity.

First up, I installed the Windows Live Translator activity and browsed to a site. Highlighting some text gave me a context menu that had the translator activity in it:

image

I thought this was quite a nice little feature... :)

 

WebSlices

Developers can mark parts of webpages as "WebSlices" and enable users to monitor information they rely on as they move about the web. With a click in the Favorites bar, users see rich "WebSlice" visuals and developers establish a valuable, persistent end-user connection.

So next I thought I'd try the Facebook WebSlice. I logged into facebook and installed the slice from the toolbar:

image

image

This put a new button in my favourites toolbar. But unfortunately, it didn't work too well...

image 

I also noticed that facebook wanted me to upgrade to IE6 or any other browser...

image

So I thought I'd try...

IE7 Emulation

Hitting the IE7 Emulation button on the toolbar actually annoyed me a little:

image

Couldn't this just emulate the tab...?

Anyway, I opened another IE window, emulated it and voila! The facebook warning disappeared. That's the extent of my testing this feature for today... :)

Other Niceties

The Developer Tools is built-in for some testing fun. I'm really looking forward to using it for sifting through page responses and comparing some of the IE7 and IE8 responses.

The "Are you sure you want to close all tabs" message that appears when you try to close IE with multiple tabs open has morphed to give you the option of just closing the current tab. I always thought a cancel button in these cases is silly because the big red cross in the top right and the Escape button are just as good.

image

The Address Bar changes how you look at the address of the current page by only making the domain name text black and the rest gray. I'm not sure whether this is for security or just usability, but I like it.

image

Comments

It's definitely RAM hungry. Only 5 tabs open and already 110MB in use...

image

It hasn't crashed in the last hour so that's good. :) I'm planning on just using it like IE7 and seeing how I go. I'll definitely keep posting about any oddities and niceties I come across.