Jacob Carpenter's blogspot

Blog Archive

Friday, November 16

New blog

For no good reason, I installed Windows Live writer and started a new blog. You can check it out at http://jacobcarpenter.wordpress.com/.

Thursday, July 26

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HelloOrcas
{
    class Program
    {
        static void Main(string[] args)
        {
            "Hello, Orcas!".Print();
        }
    }

    public static class StringExtensions
    {
        public static void Print(this string message)
        {
            Console.WriteLine(message);
        }
    }
}

Wednesday, April 4

    7 public static class CollectionHelper
    8 {
    9     public static IEnumerable<T> Enumerate<T>(params T[] args)
   10     {
   11         if (args == null)
   12             throw new ArgumentNullException("args");
   13 
   14         foreach (T arg in args)
   15             yield return arg;
   16     }
   17 
   18     public static T First<T>(IEnumerable<T> source)
   19     {
   20         return First(source, ReturnTrue);
   21     }
   22 
   23     public static T First<T>(IEnumerable<T> source, Func<T, bool> predicate)
   24     {
   25         T result;
   26         if (!TryFindFirst(source, out result, predicate))
   27             throw new InvalidOperationException("Source sequence empty or no items satisfy predicate.");
   28 
   29         return result;
   30     }
   31 
   32     public static T FirstOrDefault<T>(IEnumerable<T> source)
   33     {
   34         return FirstOrDefault(source, ReturnTrue);
   35     }
   36 
   37     public static T FirstOrDefault<T>(IEnumerable<T> source, Func<T, bool> predicate)
   38     {
   39         T result;
   40         TryFindFirst(source, out result, predicate);
   41         return result;
   42     }
   43 
   44     public static bool TryFindFirst<T>(IEnumerable<T> source, out T result)
   45     {
   46         return TryFindFirst(source, out result, ReturnTrue);
   47     }
   48 
   49     public static bool TryFindFirst<T>(IEnumerable<T> source, out T result, Func<T, bool> predicate)
   50     {
   51         if (source == null)
   52             throw new ArgumentNullException("source");
   53         if (predicate == null)
   54             throw new ArgumentNullException("predicate");
   55 
   56         foreach (T item in source)
   57         {
   58             if (predicate(item))
   59             {
   60                 result = item;
   61                 return true;
   62             }
   63         }
   64 
   65         result = default(T);
   66         return false;
   67     }
   68 
   69     public static IEnumerable<TOut> Map<T, TOut>(IEnumerable<T> source, Func<T, TOut> converter)
   70     {
   71         if (source == null)
   72             throw new ArgumentNullException("source");
   73         if (converter == null)
   74             throw new ArgumentNullException("fn");
   75 
   76         foreach (T item in source)
   77             yield return converter(item);
   78     }
   79 
   80     public static IEnumerable<TOut> Zip<TLeft, TRight, TOut>(IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TRight, TOut> fn)
   81     {
   82         if (left == null)
   83             throw new ArgumentNullException("left");
   84         if (right == null)
   85             throw new ArgumentNullException("right");
   86         if (fn == null)
   87             throw new ArgumentNullException("fn");
   88 
   89         using (IEnumerator<TLeft> leftEnumerator = left.GetEnumerator())
   90         using (IEnumerator<TRight> rightEnumerator = right.GetEnumerator())
   91         {
   92             while (true)
   93             {
   94                 bool leftMoved = leftEnumerator.MoveNext();
   95 
   96                 if (!(leftMoved == rightEnumerator.MoveNext()))
   97                     throw new InvalidOperationException("Sequences are of incompatible lengths.");
   98 
   99                 if (!leftMoved)
  100                     break;
  101 
  102                 yield return fn(leftEnumerator.Current, rightEnumerator.Current);
  103             }
  104         }
  105     }
  106 
  107     private static bool ReturnTrue<T>(T ignored)
  108     {
  109         return true;
  110     }
  111 }

Tuesday, November 14

Single Raised EventHandler

Earlier today, a friend described a scenario at his work where he needed to hook up an EventHandler that was only raised once.

A naïve solution could be to merely check whether the critical code had been executed within the handler; then set the state appropriately upon the first execution. Something like:

public class TestClass
{
   public event EventHandler SimpleEvent;

   public void RaiseAll()
   {
      if (SimpleEvent != null)
         SimpleEvent(null, EventArgs.Empty);
   }
}

// elsewhere:

TestClass test = new TestClass();

bool raised = false;
test.SimpleEvent += delegate
{
   if (!raised)
   {
      // critical code:
      raised = true;
      Console.WriteLine("Hello world!");
   }
};

test.RaiseAll();
test.RaiseAll();
test.RaiseAll();

// output:
// Hello world!

Okay, that's fine for an event on a simple, transient instance of an object. But what if, in the lifecycle of our application, we could potentially throw away hundered of EventHandlers? And what if, further complicating the problem, the event is static? It sure would be nice if we could actually remove the EventHandler, once it has been raised.

Well, we can. There are two ways to achieve this: one is simple but requires duplication for reuse; the other is complicated but easily reusable.

Let's look at the simple one first:

TestClass test = new TestClass();

EventHandler handler = null; // avoid: error CS0165: Use of unassigned local variable 'handler'
test.SimpleEvent += handler = delegate
{
   test.SimpleEvent -= handler; // remove self before executing the critical code
   Console.WriteLine("Hello world!");
};

test.RaiseAll();
test.RaiseAll();
test.RaiseAll();

// output:
// Hello world!

There are a couple of things to note here:

  1. Since we know the type of TestClass's SimpleEvent, we can declare a strongly typed EventHandler and assign an anonymous method to it. Not knowing this type at compile-time is the source of much of the complication of the reusable solution below.
  2. Also, we temporarily assign null to handler before referring to handler within the body of the anonymous method to avoid the noted compiler error. Then, we assign the anonymous method to handler before attaching handler to the event.

But, Jacob, this works fine. Why would we care about "improving" it?

Well, for starters, it's not very extensible. The critical code is embedded into the anonymous method. So anytime we want to bring different functionality to this event, we'll need to repeat this pattern. Also, not only is the critical code not pluggable, but we've constrained ourselves to only EventHandler events. There are other types of strongly typed event handling delegates with far more interesting EventArgs (and how does the name "EventArgs" not violate the Framework Design Guidelines, anyway?). And lastly, … well… because we can:

[At this point in the post, the author suddenly switches voices: the hand-holdy, instructive teacher is replaced with the programmer who has spent too much time with the material at hand and pastes in swaths of code assuming his audience will understand. Apologies for the lack of exposition to follow.]

public static class EventUtility
{
   public static void AttachRaisedOnce<TTarget>(TTarget target, string eventName, EventHandler raisedOnce)
      where TTarget : class
   {
      AttachRaisedOnce<TTarget, EventArgs>(target, eventName, CastDelegate<EventHandler<EventArgs>>(raisedOnce));
   }

   public static void AttachRaisedOnce<TTarget, TEventArgs>(TTarget target, string eventName, EventHandler<TEventArgs> raisedOnce)
      where TTarget : class
      where TEventArgs : EventArgs
   {
      EventInfo eventTarget = typeof(TTarget).GetEvent(eventName);
      if (eventTarget == null)
         throw new ArgumentException(String.Format("Couldn't find event with name '{0}'", eventName), "eventName");

      Delegate self = null; // avoid unassigned local
      EventHandler<TEventArgs> localMethod = delegate(object sender, TEventArgs e)
      {
         eventTarget.RemoveEventHandler(target, self);
         raisedOnce(sender, e);
      };

      self = Delegate.CreateDelegate(eventTarget.EventHandlerType, localMethod.Target, localMethod.Method);
      eventTarget.AddEventHandler(target, self);
   }

   // see earlier post
   // also: belongs elsewhere; maybe a static DelegateUtility class
   private static T CastDelegate<T>(Delegate source)
      where T : class // CS0702: Constraint cannot be special class 'System.Delegate'
   {
      if (source == null)
         return null;

      Delegate[] delegates = source.GetInvocationList();
      if (delegates.Length == 1)
         return Delegate.CreateDelegate(typeof(T), delegates[0].Target, delegates[0].Method) as T;

      for (int i = 0; i < delegates.Length; i++)
         delegates[i] = Delegate.CreateDelegate(typeof(T), delegates[i].Target, delegates[i].Method);

      return Delegate.Combine(delegates) as T;
   }
}

Calling code looks like:

TestClass test = new TestClass();

EventUtility.AttachRaisedOnce(test, "SimpleEvent", delegate { Console.WriteLine("Hello world!"); });

test.RaiseAll();
test.RaiseAll();
test.RaiseAll();

// output:
// Hello world!

For strongly typed EventHandlers, like the System.Web.UI.ImageClickEventHandler delegate, the calling code looks a little weird:

EventUtility.AttachRaisedOnce<ImageButton, ImageClickEventArgs>(button, "Click", delegate { Response.Write("Hello web!"); });

Note that the second type argument is the type of the EventArgs, not the type of the EventHandler delegate itself. This is due to the inablity to apply a Delegate constraint on a type argument, coupled with the need to assign an anonymous method to a local variable with the right type. We rely on the fact that we can convert from an EventHandler<T> to the strongly typed EventHandler delegate. This means that it is also possible to compile code with the wrong event/delegate combinations; but don't worry: the runtime will "inform you" of any conversion failures.

Enjoy.

Friday, November 3

Enum TryParse

I was somewhat surprised to discover that there's no TryParse method for the Enum class in the .NET Framework 2.0. (It's also odd that the docs/compiler keep referring to Enum as a class—and yet the apprpriate where constraint to apply is struct.) So here's a pair of generic methods to support TryParse for Enums:

public static class EnumUtility
{
   public static bool TryParse<T>(string value, out T result)
      where T : struct // error CS0702: Constraint cannot be special class 'System.Enum'
   {
      return TryParse<T>(value, out result, false);
   }

   public static bool TryParse<T>(string value, out T result, bool ignoreCase)
      where T : struct // error CS0702: Constraint cannot be special class 'System.Enum'
   {
      result = default(T);
      try
      {
         result = (T)Enum.Parse(typeof(T), value, ignoreCase);
         return true;
      }
      catch { }

      return false;
   }
}

Tuesday, October 17

Enumerate Using

If you ever need to enumerate a collection of IDisposable items, and you find the following code snippet ugly:

foreach (SomeDisposableClass item in collectionOfDisposableItems)
{
   using (item)
   {
      // do stuff
   }
}

You may find the following method useful:

public static IEnumerable<T> EnumerateUsing<T>(IEnumerable<T> disposableItems)
   where T : IDisposable
{
   foreach (T item in disposableItems)
      using (item)
         yield return item;
}

Calling code looks like:

foreach (SomeDisposableClass item in EnumerateUsing(collectionOfDisposableItems))
{
   // do stuff
}

And yes, Dispose() does get called appropriately after you're finished "doing stuff".

Friday, October 6

Merging in Subversion

Once you've done it, merging from a branch to the trunk (or vice versa) in Subversion is a trivial task. But that first time you attempt it, it can seem a little daunting. Here's a quick how-to:

  1. Let's say you've got a development branch that's all committed and ready to be merged into the trunk. First, switch your working copy to where the result of the merge will ultimately be committed; in this case, the trunk.
  2. merge from the current location to the location that resembles your desired final result; for us, this is merging from the trunk to the development branch.
  3. Resolve any conflicts and commit your current working copy.

Friday, September 15

Visual Studio Macro

Never thought I'd be posting VB to my blog, but here's a little Visual Studio macro to switch between a Class file and it's associated TestFixture. The macro assumes a ClassNameFixture naming convention. Also sorry if my VB sucks, it literally took me 3 minutes plus asking a coworker to figure out how test for null.

Enjoy:

Imports System
Imports System.IO
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module TestFixtures

    Public Sub SwitchBetweenClassAndFixture()
        Dim active As Document, filename As String, extension As String
        Const fixtureSuffix = "Fixture"

        active = DTE.ActiveDocument
        If Not active Is Nothing Then
            filename = Path.GetFileNameWithoutExtension(active.Name)
            extension = Path.GetExtension(active.Name)
            If filename.EndsWith(fixtureSuffix) Then
                DTE.ExecuteCommand("Edit.OpenFile", filename.Substring(0, filename.Length - fixtureSuffix.Length) + extension)
            Else
                DTE.ExecuteCommand("Edit.OpenFile", filename + fixtureSuffix + extension)
            End If
        End If
    End Sub

End Module

Wednesday, August 2

Generics and Delegates

I see a surprising number of search hits on this blog for things involving generics, delegates, and collections. So I guess it would be appropriate to write a series of posts on the subject.

This is all pretty rudimentary stuff, so if you're familiar with generics, delegates, and anonymous methods, you may want to just skip this one.

Generics

public static class Assert
{
    public void Throws<T>(/* ... */) where T: Exception {/* ... */}
}

Here we have a method, named as if it were a part of some test framework (say, NUnit). This method takes one type parameter (T), so we can call this method a "generic method".

This method also contains what is called a "type constraint". That bit beginning with where says that any type that stands in for T must derive from (or be) System.Exception. There are other types of… well… type constraints that I don't think I'll cover in this post.

Okay, so what would we need to know to see if a block of code threw a specific exception? Obviously the type of exception we would expect—that's T. But we would also need the block of code, wouldn't we?

Delegates / Anonymous methods

Delegates have been in C# since forever. Event handling in Forms (and Web Forms) uses delegates extensively. So what's the big fuss?

Well, C# 2.0 introduces the very useful concept of anonymous methods. Arbitrary blocks of code that can be passed around and executed at whim.

Wheras before one had to define a method corresponding to a specific delegate's signature, and then construct the delegate (using syntax that still feels a little odd) before being able to pass it around, you can now say:

public delegate void VoidNoArg();

// ...

VoidNoArg myCode = delegate { Console.WriteLine("Hello world!"); };

Neat. But how useful can a void, no argument delegate really be? Very, actually, through the magic of closures. That is, you can actually say:

string greeting = "Hello world!";

VoidNoArg myCode = delegate { Console.WriteLine("Hello world!"); };
VoidNoArg myCode = delegate { Console.WriteLine(greeting); };

myCode();

// output: Hello world!

Note that the anonymous method referrs to a variable outside of its own scope.

Putting it together

public static class Assert
{
    public void Throws<T>(VoidNoArg code) where T: Exception {/* ... */}
}

// ...

int i = Int32.MaxValue;
Assert.Throws<OverflowException>(delegate { checked(i + 1); });

That's just the tip of the iceberg.

Delegates can be generic. Classes can be generic. Generic classes can have methods that take generic delegates. The System.Collections.Generic collections do all of these things. We'll look at this more in a future post…

Tuesday, July 18

Ruby Closures

This guide covering closures in Ruby by Paul Cantrell is very insightful. It's written as a Ruby script to be both executed and read. Thanks to Ruby Inside for linking to it.