Have language features changed the way we work for the better?

Craig Murphy dropped a little coding challenge on his blog the other day. This prompted me to write the responses as below. I’ve tried to target each one towards using a particular technology as the framework has developed. Have a look and tell me which is your preferred answer, or propose a new one (but again try to target a language feature). I’d love to know who you why you choose that language feature over another. Option 1. With Linq private const string alphabet = "abcdefghijklmnopqrstuvwxyz";   static void Main(string[] args) { char c = Console.ReadKey().KeyChar;   var myChars = from character in alphabet where character <= c select character;   var fullRow = myChars.Skip(1).Reverse().Concat(myChars);   var myRows = (from character in myChars select ConvertToSpaces(character, fullRow));   var reverseRows = myRows.Reverse().Skip(1); myRows = myRows.Concat(reverseRows);   Console.WriteLine(Environment.NewLine);//Skip the ReadKey line foreach (string line in myRows) Console.WriteLine(line);   Console.ReadKey(); }   private static string ConvertToSpaces(char wanted, IEnumerable<char> characters) { return new string( (from character in characters select character == wanted ? character : ' ').ToArray()); } Option 2. With Generics   class Program { private const string alphabet = "abcdefghijklmnopqrstuvwxyz";   static void Main(string[] args) { char c = Console.ReadKey().KeyChar;   List<char> myChars = new List<char>(); foreach (char character in alphabet) { if (character <= c) myChars.Add(character); }   List<char> temp = new List<char>(Reverse<char>(AllButFirst<char>(myChars))); temp.AddRange(myChars); string fullRow = new string(temp.ToArray());   List<string> myRows = new List<string>(); foreach (char character in myChars) { myRows.Add(ConvertToSpaces(character, fullRow)); }   IEnumerable<string> reverseRows = AllButFirst<string>(Reverse<string>(myRows)); myRows.AddRange(reverseRows);   Console.WriteLine(Environment.NewLine);//Skip the ReadKey line foreach (string line in myRows) Console.WriteLine(line);   Console.ReadKey(); }   private static IEnumerable<T> Reverse<T>(IEnumerable<T> myChars) { Stack<T> reverse = new Stack<T>(); foreach (T character in myChars) { reverse.Push(character); } while (reverse.Count > 0) { yield return reverse.Pop(); } }   private static IEnumerable<T> AllButFirst<T>(IEnumerable<T> myChars) { bool first = true; foreach (T character in myChars) { if (first) first = false; else yield return character; } }   private static string ConvertToSpaces(char wanted, IEnumerable<char> characters) { StringBuilder result = new StringBuilder(); foreach (char character in characters) { result.Append(character == wanted ? character : ' '); } return result.ToString(); } } Option 3. Using IEnumerable   class ProgramDNv2 { private const string alphabet = "abcdefghijklmnopqrstuvwxyz"; static void Main(string[] args) { DiamondChars diamond = new DiamondChars(); diamond.chars = GetChars( Console.ReadKey().KeyChar); foreach (string line in diamond) { Console.WriteLine(line); } Console.ReadKey(); }   private static string GetChars(char MidChar) { string chars = alphabet.Substring(0, alphabet.IndexOf(MidChar) + 1); return chars; }   private class DiamondChars : IEnumerable<String> { public string chars;   #region IEnumerable<string> Members   public IEnumerator<string> GetEnumerator() { int index = 0; foreach (char character in chars) { yield return MakeLine(character, index); index++; } index--; foreach (char character in chars.Reverse()) { if (index < chars.Length - 1) { yield return MakeLine(character, index); } index--; } }   #endregion   private string MakeLine(char character, int index) { string line = new string(chars[index], 1).PadLeft(chars.Length - index);   if (index > 0) return line + new string(chars[index], 1).PadLeft(index * 2); else return line; }   #region IEnumerable Members   System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }   #endregion }   } Option 4. Simple recursion   class ProgramDNv1 { static void Main(string[] args) { string input = "abcde"; StringBuilder result = new StringBuilder(); BuildDiamond(0, input, result); Console.WriteLine(result); }       private static void BuildDiamond(int index, string input, StringBuilder result) { string line = new string(input[index], 1).PadLeft(input.Length - index); string line2 = new string(input[index], 1).PadLeft(index * 2); result.Append(line); if (index > 0) result.Append(line2); result.Append(Environment.NewLine); if (index < input.Length - 1) { BuildDiamond(index + 1, input, result); result.Append(line); if (index > 0) result.Append(line2); result.Append(Environment.NewLine); } } } Now add a quick comment below telling you preferred implementation and briefly why. Thanks.

Proxy authentication with retry

Need to talk through a proxy? Try this. You'll probably want to refactor in a factory method to allow the correct creation and re-creation of the WebRequest. Note that attempt one uses the default proxy with Windows authentication parameters, subsequent attempts ask for a user name and password. Or at least they will once you convert the comment into a nice call to a GUI. int retries = 0; bool retry = false;   HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://alski.net"); HttpWebResponse response = null;   do { try { Console.WriteLine("Attempt " + retries.ToString()); response = (HttpWebResponse)request.GetResponse();   Console.WriteLine("Success"); } catch (WebException wex) { Console.WriteLine(wex.Message); if ( ((HttpWebResponse)wex.Response).StatusCode == HttpStatusCode.ProxyAuthenticationRequired) { //Can't change proxy after request has been submitted so we recreate the request request = (HttpWebRequest)WebRequest.Create(request.RequestUri); switch (retries++) { case 0: retry = true; request.Proxy = WebRequest.GetSystemWebProxy(); break; case 1: case 2: case 3: request.Proxy = WebRequest.DefaultWebProxy; //Show form to ask for credentials and maybe change proxy request.Proxy.Credentials = new NetworkCredential("user", "passsword"); break;   default: retry = false; break; } } } } while (response == null && retry);

Strongly typed DAL reader

I wrote this little piece of code a while ago, and the more I see it the more I'm proud of it. It allows you to create strongly typed objects from each row of a data result, and yield them, so you can dispose them individually without needing the whole list in memory. It also filters out null results so you can correlate data from external sources. public delegate T CreationVisitor<T>(SqlDataReader reader); public IEnumerator<T> Select<T>(CreationVisitor<T> visitor, string sql) { using (SqlConnection connection = new SqlConnection(_connectionString)) { connection.Open(); using (SqlCommand shredderCommand = new SqlCommand(sql, connection)) { shredderCommand.CommandTimeout = _timeOut; using (SqlDataReader reader = shredderCommand.ExecuteReader(CommandBehavior.SingleResult)) { while (reader.Read()) { T dalObject = visitor(reader); if (dalObject != null) yield return dalObject; } } } } } Called as return houseKeeper.Select<AuditContent>( delegate(SqlDataReader reader) { string shredderFilename = (string)reader["file_name"].ToString(); …etc if (File.Exists(guidFilename)) { return new AuditContent(shredderFilename); } return null; }, sql);   I'll have to try the re-write as a 3.5 Lambda function, it would be very terse then.

The syntax for an anonymous delegate

I seem to have problems remembering the syntax remembering the syntax for anonymous delegates, so here it is. return GetUnfilteredList().FindAll(new Predicate<MyObject>( delegate (MyObject instance) {     return (instance.IsWanted)); })); What strikes me as a write this though is how confusing it is that the delegate doesn't have a return type. Maybe that's why I can never remember the syntax.  

So how does assembly load work

Cameron and myself were wondering what actually happens in various scenarios and so we came up with some Unit Tests. What we found With local dlls it tries several paths bin/Debug/TestAssembly.DLL. bin/Debug/TestAssembly/TestAssembly.DLL. bin/Debug/TestAssembly.EXE. bin/Debug/TestAssembly/TestAssembly.EXE. You need a full strong name to load from the GAC all four parts You can get a strong name by attempting to load a dll locally i.e. if you have a local dll with a strongname you can attempt to load it without a full strongname, and the local dll will be read to get the strongname and then the dll can be read FROM THE GAC Yes, this last item seems a little insane, but please try the unit test if you don’t believe me. Please let me know if you can think of more test scenarios to add.

Streaming ForEach using a yield

I've been looking for an article on converting foreachs into a less memory intensive operation and I remember reading http://msdn2.microsoft.com/en-us/vcsharp/bb264519.aspx before, I just couldn't find it.  Basically it uses an example of all numbers in the New York phone book to develop a means of streaming the loops using custom iterators using yield instead of loading it all in and looping through it all.

Why List&lt;T&gt;.Foreach missed the boat AKA The great 'Personal threading maturity model' barrier

With dotnet2.0 there a great set of functions added onto the generic list classes and their associates. I am particularly fond of anything which makes use of Predicate<T> like filter, but I've recently realised that this functionality is flawed. The great 'Personal threading maturity model' barrier How capable do you rate yourself with multi-threading? Fairly well, but that's a bit subjective isn't it. Have a quick look at the 'Personal threading maturity model', and hopefully you can give a more objective rating now. Until recently I was naive, probably a 2-3 on the Maturity model. I've used background workers to ease the UI and used lock based data structures to negotiate concurring problems. Breaking the barrier it may not be clear on today's hardware that further learning is necessary. Unfortunately, since manycore machines are not yet available Larry O'Brien - January 2007 Well its now October 2007, and he was spot on. Personally I am starting to see my knowledge grow exponentially at the moment, and I can put it down to two factors. Now I've replaced my old machine, I've become core aware. Multi-threading is now required to avoid the 50% flat out CPU graph. At work, we are building a multi-processing system. Basically think of a big queue and a farm of application servers. Each application server picks up what it can handle according to current CPU/Memory constraints. In both cases, the whole thing becomes a lesson in creating chunks of code that can be run in parallel. The easy bit is where we have piece of data and it goes through one path of logic. The challenge is where we have loops. List<T>.Foreach I now think that this functionality will NEVER be used. It will be consigned to the 'nice shame I doesn't respect manycore' bin. Instead people will be looking for MapReduce functionality, of which there are quite a few implementations already. Joel kicked off a rush of these implementations with his post Can Your Programming Language Do This?. http://www.ericsink.com/entries/multicore_map.html Strange, I can't find any other implementations, well that is apart from my own and that reeds refining yet. Instead we want List<T>.Map(Predicate<T> fn) and List<T>.Reduce(Predicate<T> fn) and the only problem is they don't exist yet.

AssemblyName.ReferenceMatchesDefinition is missing in MSDN

Strangely the static AssemblyName.ReferenceMatchesDefinition function is rather poorly documented in the MSDN documentation that came with my copy of Visual Studio 2005It does seem to work the way the name suggests.UpdateMSDN online has the correct info.Junfeng Zhang as always comes up with the implicit workingsAssemblyName.ReferenceMatchesDefinition Assembly Identity --- ReferenceIdentity and DefinitionIdentity, Comparison and Transformation

To VS2005 or not...

SummaryPros and Cons of upgrading to Visual Studio 2005 and dotNet 2.0 DotNet2.0 What's new http://msdn2.microsoft.com/en-US/library/7cz8t42e(VS.80).aspx and http://msdn2.microsoft.com/en-US/library/t357fb32.aspx Pros Assemblies should just compile. However there will be a large number of warnings. These can be switched off with either an attribute on the method(Visual Studio 2005 gives you a help link detailing this) or by using the #pragma warning in the file. Cons Deployment of ASP.NET seems very different. While web sites compiled against dotnet1.1 will just work when the server is updated to dotnet2.0, there does seem to be a big difference in the output of a dotnet2.0 compilation seems very different (unless that's just in debug) Visual Studio 2005 Pros Backwards compatibilty If you download MSBEE from http://msdn.microsoft.com/vstudio/downloads/tools/msbee/default.aspx then you can compile against dotnet1.1 or dotnet2.0 ASP.Net Web deployment now built into Studio 2005 IDE Integrated reSharper Refactor support built in (Method extraction, find ALL references, Rename) Smart Tag support in IDE (Shift-Alt-F10) provides access to unknown types, or rename vars Rename vars with Preview Data support Hugely improved Stongly typed dataset support in IDE - although investigation maybe needed to work out how to use with <XXXX>Framework Cons Will require upgrade, so costs for new licence. The project files and solutions are in a new format. Studio automatically performs the conversion for you, BUT you can't save in a backwards compatible format. i.e. Unless everybody moves to VS2005 then we will either end up with parallel project files or developers using VS2005 cannot check in changes to projects into Version control.

When Off is actually On

Strange as it seems but “Server encountered an internal error. For more information, turn on customErrors in the server’s .config file.” is actually begging for you to add, <system.runtime.remoting>     <customErrors mode="off"/> </system.runtime.remoting>  Thanks go to Chris Taylor for pointing this out. I didn't think it ever seemed to work properly before! http://dotnetjunkies.com/WebLog/chris.taylor/articles/5566.aspx