Extension Methods - TimRayburn.Extensions Beta v0.1

I've had a chance over the last few days to play some more with the March CTP of Visual Studio Codename "Orcas" and with the features being added as a part of C# 3.0.  Even while feeling utterly handicap in Visual Studio without CodeRush and Refactor! Pro, I've managed turn out an interesting little assembly that I intend to grow as time goes with the namespace TimRayburn.Extensions.  As you might guess this assembly contains Extension methods to classes within the Framework. In case you don't know what extension methods are, they are static methods in static classes which use a special syntax to indicate that they extend an existing class or interface.  For instance you might write some code like: 1: public static string ToStringNullSafe(this object inStr) 2: { 3: if (inStr == null) return string.Empty; 4: else 5: { 6: string lStr = inStr.ToString(); 7: if (lStr == null) return string.Empty; 8: else return lStr; 9: }10: } Which extends the class System.Object to contain a new method called ToStringNullSafe which, as you can see, returns String.Empty instead of throwing Exceptions when a the object being called is null or it's ToString value is null.  The intellisense for this looks like the image to the right.I intend to use TimRayburn.Extensions to contain extension methods which I've written and find useful.  Version 0.1 addresses very simple problems, but over time I'm sure more complex functions will be added.  For now there are two classes in the project FrameworkExtensions and EnsureExtensions.Framework Extensions contains three methods today.  ToStringNullSafe (as seen above) extends System.Object to provide a ToString method which will not throw exceptions on null.  ToInt32 extends System.String to provide the ability to convert to a System.Int32 inline.  Likewise ToDouble extends System.String for conversion to System.Double.  These extensions are simple and without a unifying purpose other than that I thought they would come in handy.  Nothing being done here, or in EnsureExtensions, that can't be done without extension methods, just easier and more reader friendly code.EnsureExtensions contains many methods which extend either System.Object, System.String or objects which implement IComparable<T>.  Every method in this class follows the naming convention EnsureX where X is something you would want to confirm about the datatype before using it in code.  The first of these is EnsureNotNull, an extension to System.Object, which checks if the object being used is null, and if it is throws an ArgumentException but if not it simply returns the object.  This allows for interesting pieces of code like: 1: public void MyExampleMethod(string inputData) 2: { 3: inputData.EnsureNotNull().EnsureGreaterThan("Bravo").EnsureLessThan("Charlie"); 4:   5: // Real code here now that arguments have been checked. 6: }The observant among you might notice that this sort of methodology could also be extended to handle NUnit Assert's, and I assure you that has not gone unnoticed by me.  Extension methods may very well provide some interesting Syntactic Glue for many things in the future.  Not rocket science, but very cool, and in my opinion very readable.You can download the code for this below, though you will need the CTP of Orcas to compile this code.Download TimRayburn.Extensions

Patterns & Practices on Team System

The Patterns & Practices division over at Microsoft is starting a Wiki on Team System best practices and guidance and they're using CodePlex to do it.  If your thing is Team System this is a great way to interact with the team by both learning and offering suggestions in their discussion area. (Hat Tip Larkware)

LINQ Bug or Feature?

So after many hours of downloading I've acquired the March CTP for Orcas and have it running both at home and at work under Virtual PC 2007.  I decided to jump into LINQ as I'm entirely jazzed about this but one of my first few experiments with it, while a little unorthodox, has me scratching my head a bit. Consider if you will the following code, which retrieves a list of all files in the root folder of the C drive and then, using LINQ, selects a set of them at random using the FlipACoin method.  Then I iterate through the list, outputting the contents of the results of my query ... or so I thought. 1: using System; 2: using System.Linq; 3: using System.Collections.Generic; 4: using System.Text; 5:   6: namespace TestConsole07 7: { 8: class Program 9: {10: static Random rnd = new Random();11:  12: static void Main(string[] args)13: {14: var myList =15: from f in System.IO.Directory.GetFiles(@"C:\")16: where FlipACoin()17: select System.IO.Path.GetFileName(f);18:  19: Console.WriteLine();20: Console.WriteLine("First Loop");21: Console.WriteLine("-----------");22: foreach (string loopFile in myList)23: {24: Console.WriteLine(loopFile);25: }26:  27: Console.WriteLine();28: Console.WriteLine("Second Loop");29: Console.WriteLine("-----------");30: foreach (string loopFile in myList)31: {32: Console.WriteLine(loopFile);33: }34:  35: Console.WriteLine();36: Console.WriteLine("Press Enter To Exit");37: Console.ReadLine();38: }39:  40: static bool FlipACoin()41: {42: return rnd.Next() > (int.MaxValue / 2);43: }44: }45: }When this code is executed, what happens is very odd.  Here is the output from a sample run:First Loop----------AUTOEXEC.BATeula.1033.txtinstall.iniinstall.res.1033.dllMSDOS.SYSNTDETECT.COMntldrpagefile.syssde.bmpSDE_VSD.MSIunicows.dll Second Loop-----------boot.iniCONFIG.SYSinstall.exeinstall.iniinstall.res.1033.dllNTDETECT.COMSDE_VSD.MSIunicows.dll Press Enter To ExitNotice that despite the fact that I'm iterating over the same list each time, the files listed are different.  This means that each time I begin to iterate over the list the LINQ "query" is being executed again, and a new set of values are being returned from FlipACoin. I can undoubtedly say this wasn't what I expected, but what I can't seem to determine is if this is a feature of LINQ or if this is a bug.  My first response would be bug, but that is because whenever I believe I've expressed my intent clearly and don't get the response I expect, I call that a bug. What do you think?  Is this just a cool feature that won't come up very often? Or is this a dent in the armor of LINQ?