The Weekly Source Code 7
In my new ongoing quest to read source code to be a better developer, I now present the seventh in an infinite number of a weekly series called "The Weekly Source Code." Here's some source I'm reading this week that I enjoyed.
I got a little sidetracked the recent trip to the ALT.NET conference, so forgive me for missing last week.
- Joe Cheng's Schwartzian Transform in C# 3.0 - Whenever someone knows the official name for technique, be it in chess or in code, they're usually smarter than I. "You are using Bonetti's Defense against me, ah?" Joe is one of those guys. ;)
"What’s a Schwartzian Transform? It’s a way of efficiently sorting a list of objects according to some potentially expensive-to-calculate property of those objects. For example, let’s say you have an array of filenames, and you want to sort them by their last modified dates"
This is a very useful technique to know and nice and clean in C# 3.0.
public static List<TElement> SortBy2<TElement, TSortBy>( this List<TElement> coll, Converter<TElement, TSortBy> converter, Comparison<TSortBy> comparison) { return coll .ConvertAll(el => new { Key = converter(el), Value = el }) .Sort((a, b) => comparison(a.Key, b.Key)) .ConvertAll(x => x.Value); }
This is what I call Left-Hand/Right-Hand code where we're pulling with one hand, in this case XML and handing off with the other hand, in this case, making a LINQ List. It tends to be very tedious but LINQ sure makes it easy.
XNamespace ns = NAMESPACE_AWSECommerceService; var books = from book in booksDoc.Descendants(ns+"Item") select new Book { Title = book.Element(ns+"ItemAttributes").Element(ns+"Title").Value, Publisher = book.Element(ns+"ItemAttributes").Element(ns+"Publisher").Value, Year = uint.Parse(((String)book.Element(ns+"ItemAttributes").Element(ns+"PublicationDate").Value).Substring(0, 4)), Authors = ( from author in book.Descendants(ns+"Author") select (String) author.Value ).ToList() };
There is far too much to paste much here, but what are the things I click away was a new attribute but I hadn't heard of yet. You can tell FxCop to relax as they do here with a naming rule.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Rss")] public class RssFeedCreatedEventArgs : EventArgs, IComparable {...
var pixelsQuery = from y in Enumerable.Range(0, screenHeight) let recenterY = -(y - (screenHeight / 2.0)) / (2.0 * screenHeight) select from x in Enumerable.Range(0, screenWidth) let recenterX = (x - (screenWidth / 2.0)) / (2.0 * screenWidth) let point = Vector.Norm(Vector.Plus(scene.Camera.Forward, Vector.Plus(Vector.Times(recenterX, scene.Camera.Right), Vector.Times(recenterY, scene.Camera.Up)))) let ray = new Ray { Start = scene.Camera.Pos, Dir = point } let computeTraceRay = (Func<Func<TraceRayArgs, Color>, Func<TraceRayArgs, Color>>) (f => traceRayArgs => (from isect in from thing in traceRayArgs.Scene.Things select thing.Intersect(traceRayArgs.Ray) where isect != null orderby isect.Dist let d = isect.Ray.Dir let pos = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start) let normal = isect.Thing.Normal(pos) let reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal)) let naturalColors = from light in traceRayArgs.Scene.Lights let ldis = Vector.Minus(light.Pos, pos) let livec = Vector.Norm(ldis) let testRay = new Ray { Start = pos, Dir = livec } let testIsects = from inter in from thing in traceRayArgs.Scene.Things select thing.Intersect(testRay) where inter != null orderby inter.Dist select inter let testIsect = testIsects.FirstOrDefault() let neatIsect = testIsect == null ? 0 : testIsect.Dist let isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0)) where !isInShadow let illum = Vector.Dot(livec, normal) let lcolor = illum > 0 ? Color.Times(illum, light.Color) : Color.Make(0, 0, 0) let specular = Vector.Dot(livec, Vector.Norm(reflectDir)) let scolor = specular > 0 ? Color.Times(Math.Pow(specular, isect.Thing.Surface.Roughness), light.Color) : Color.Make(0, 0, 0) select Color.Plus(Color.Times(isect.Thing.Surface.Diffuse(pos), lcolor), Color.Times(isect.Thing.Surface.Specular(pos), scolor)) let reflectPos = Vector.Plus(pos, Vector.Times(.001, reflectDir)) let reflectColor = traceRayArgs.Depth >= MaxDepth ? Color.Make(.5, .5, .5) : Color.Times(isect.Thing.Surface.Reflect(reflectPos), f(new TraceRayArgs(new Ray { Start = reflectPos, Dir = reflectDir }, traceRayArgs.Scene, traceRayArgs.Depth + 1))) select naturalColors.Aggregate(reflectColor, (color, natColor) => Color.Plus(color, natColor))) .DefaultIfEmpty(Color.Background).First()) let traceRay = Y(computeTraceRay) select new { X = x, Y = y, Color = traceRay(new TraceRayArgs(ray, scene, 0)) }; foreach (var row in pixelsQuery) foreach (var pixel in row) setPixel(pixel.X, pixel.Y, pixel.Color.ToDrawingColor());
Feel free to send me links to cool source that you find hasn't been given a good read.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
I used what is perhaps one of the oldest code generators ever: fingers. I had been using the Visual Studio Team System unit tests, but was hesitant to provide them as not everyone is using the team suite. Other than NUnit, do you have any recommendations on a testing framework to utilize?
I'm all for reading code - shame it doesent format in Outlook 2007 correctly as i use the RSS features of that.
Totally off topic, but have you heard of Thinstall? www.thinstall.com
I think you would have a ball with it... *application* virtualization for Windows.
Ironically I had been thinking about this in the last couple of days... the ability to have an anonymous type to hold {value, key} makes this very easy to do.
Just a shame I appear to be several months late in putting two and two together to get five :-).
Comments are closed.
I can't wait to see functional programming mindsets become more prevalent in our imperative world. Maybe one day I can happily say bye bye to Haskell.