LINQ to SQL, Lambda, Generics and Readability

In my previous (and perhaps still ongoing) article series about LINQ to SQL Performance Optimization I demonstrated code that builds up a LINQ to SQL hierarchy using parts that had been loaded unconnected.

The code to hook up the hierarchy looked a bit messy, so I decided to try to clean it up. What I came up with was much cleaner. But is it more readable? I’m not so sure, my point with this post is this, be careful with what clever methods you introduce, because in the end, they might not be more readable than doing it the hard way. And let’s face it, readability is more important than brevity… at least sometimes…

The brief version

Note that with the supporting methods, this method is more verbose – but the supporting methods could be re-used over and over again…

The actual method that performs the assembling;

        public static List<Supplier> AssembleHierarchyTight(List<Supplier> suppliers, List<Product> products, List<Category> categories, List<Order_Detail> orderDetails, List<Order> orders, List<Shipper> shippers, List<Customer> customers)
        {
            LoadFrom(suppliers, supplier => supplier.Products, (supplier, product) => supplier.SupplierID == product.ProductID, products);
            LoadFrom(products, supplier => supplier.Category, (supplier, category) => supplier.CategoryID == category.CategoryID, categories);
            LoadFrom(products, supplier => supplier.Order_Details, (supplier, orderDetail) => supplier.ProductID == orderDetail.ProductID, orderDetails);
            LoadFrom(orderDetails, detail => detail.Order, (detail, order) => detail.OrderID == order.OrderID, orders);
            LoadFrom(orders, order => order.Shipper, (order, shipper) => order.ShipVia == shipper.ShipperID, shippers);
            LoadFrom(orders, order => order.Customer, (order, customer) => order.CustomerID == customer.CustomerID, customers);           

            return suppliers;
        }

The support methods;

        public static void LoadFrom<TDestination, TTarget>(
            IEnumerable<TDestination> destinations,
            Expression<Func<TDestination, EntitySet<TTarget>>> expression,
            Func<TDestination, TTarget, bool> comparator,
            IEnumerable<TTarget> sources)
            where TTarget : class
        {
            PropertyInfo property = TypeHelper.FindProperty(expression);
            List<TTarget> sourceList = sources.ToList();
            foreach (TDestination destination in destinations)
            {
                List<TTarget> filtered =
                    sourceList
                        .Where(source => comparator(destination, source))
                        .ToList();

                EntitySet<TTarget> target = (EntitySet<TTarget>)property.GetValue(destination, _emptyIndex);
                target.SetSource(filtered);
            }
        }

        public static void LoadFrom<TDestination, TTarget>(
            IEnumerable<TDestination> destinations,
            Expression<Func<TDestination, TTarget>> expression,
            Func<TDestination, TTarget, bool> comparator,
            IEnumerable<TTarget> sources)
            where TTarget : class
        {
            PropertyInfo property = TypeHelper.FindProperty(expression);
            List<TTarget> sourceList = sources.ToList();
            foreach (TDestination destination in destinations)
            {
                TTarget filtered =
                    sourceList
                        .SingleOrDefault(source => comparator(destination, source));

                property.SetValue(destination, filtered, _emptyIndex);
            }

The verbose version

This method doesn’t require any support methods;

        public static List<Supplier> AssembleHierarchyVerbose(List<Supplier> suppliers, List<Product> products, List<Category> categories, List<Order_Detail> orderDetails, List<Order> orders, List<Shipper> shippers, List<Customer> customers)
        {
            suppliers.ForEach(
                supplier => supplier.Products.SetSource(products.Where(product => product.SupplierID == supplier.SupplierID)));

            products.ForEach(
                product =>
                {
                    product.Category = categories.Single(category => category.CategoryID == product.CategoryID);
                    product.Order_Details.SetSource(
                        orderDetails.Where(detail => detail.ProductID == product.ProductID));
                });

            orderDetails.ForEach(
                detail =>
                {
                    detail.Order = orders.Single(order => order.OrderID == detail.OrderID);
                });

            orders.ForEach(
                order =>
                {
                    order.Shipper = shippers.Single(shipper => shipper.ShipperID == order.ShipVia);
                    order.Customer = customers.Single(customer => customer.CustomerID == order.CustomerID);
                });

            return suppliers;
        }

Using lambda to manipulate images

Working with every pixel in an image – the lambda way!

When working with images, I frequently need to apply the same function to every pixel in the image. Since I do that a lot, I decided to create some nice lambda image processing extensions!

In C# Win32, you would typically work with the System.Drawing.Bitmap class, so that’s what I’ll use. In C# WPF, there are other classes you’d use instead, but I won’t go into that in this blog post.

Initially I’ll use two methods, one that allows me to compute the color of each pixel in the image. Another that allows me to perform an arbitrary action for each pixel in the bitmap – the action could set the color of the pixel, but it’s not required.

Here are my extension methods for image manipulation;

using System;
using System.Drawing;

namespace LambdaImageProcessing.Core
{
    public static class BitmapExtensionMethods
    {
        public static void ExecuteForEachPixel(this Bitmap bitmap, Action<Point, Bitmap> action)
        {
            Point point = new Point(0, 0);
            for (int x = 0; x < bitmap.Width; x++)
            {
                point.X = x;
                for (int y = 0; y < bitmap.Height; y++)
                {
                    point.Y = y;
                    action(point, bitmap);
                }
            }
        }

        public static void ExecuteForEachPixel(this Bitmap bitmap, Action<Point> action)
        {
            Point point = new Point(0, 0);
            for (int x = 0; x < bitmap.Width; x++)
            {
                point.X = x;
                for (int y = 0; y < bitmap.Height; y++)
                {
                    point.Y = y;
                    action(point);
                }
            }
        }

        public static void SetEachPixelColour(this Bitmap bitmap, Func<Point, Color> colourFunc)
        {
            Point point = new Point(0, 0);
            for (int x = 0; x < bitmap.Width; x++)
            {
                point.X = x;
                for (int y = 0; y < bitmap.Height; y++)
                {
                    point.Y = y;
                    bitmap.SetPixel(x, y, colourFunc(point));
                }
            }
        }

        public static void SetEachPixelColour(this Bitmap bitmap, Func<Point, Color, Color> colourFunc)
        {
            Point point = new Point(0, 0);
            for (int x = 0; x < bitmap.Width; x++)
            {
                point.X = x;
                for (int y = 0; y < bitmap.Height; y++)
                {
                    point.Y = y;
                    bitmap.SetPixel(x, y, colourFunc(point, bitmap.GetPixel(x, y)));
                }
            }
        }
    }
}

Using my lambda method to draw the color of each pixel as a gradient given the distance to the center of the image. That code looks like this;

        private void renderDistanceFromCenterButton_Click(object sender, EventArgs e)
        {
            // Build the bitmap
            Bitmap bitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
            Point imageCenter = new Point(pictureBox.Width / 2, pictureBox.Height / 2);

            // Ok, this is terrible, you _really_ shouldn't use lambda like this... But you can...
            Func<double, double, double> distance = (x, y) => Math.Sqrt(x * x + y * y);

            double maxDistance = distance(imageCenter.X, imageCenter.Y);
            bitmap.SetEachPixelColour(
                point =>
                {
                    // Pythagoras
                    double dist = distance((point.X - imageCenter.X), (point.Y - imageCenter.Y));
                    byte b = Convert.ToByte(255 * dist / maxDistance);
                    return Color.FromArgb(b, b, b);
                });
            pictureBox.Image = bitmap;
        }

Running this code produces this image;

DistanceFromCenter

Not very pretty, but it works. And I didn’t have to write a single loop, which I find myself doing over and over again when not using lambda functions.

Make image black and white

Converting a color image to black and white can be done this way;

        private void makeBWButton_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = new Bitmap("lena.jpg");
            bitmap.SetEachPixelColour(
                (point, color) =>
                {
                    // Simplest way for making BW
                    byte b = (byte)((color.R + color.B + color.G) / 3);
                    return Color.FromArgb(b, b, b);
                });
            pictureBox.Image = bitmap;
        }

Here’s Lena in color;

lena

And with the BW method above;

lenaBW

Tinting an image – method 1

If you have an image that you wish to tint (mix it with a color) – for instance make it sepia toned – you can use this method;

        public static Color TintColor(Color originalColor, Color tintColor, byte strength)
        {
            byte s1 = (byte)(100 - strength);
            return
                Color.FromArgb(
                (s1 * originalColor.R + strength * tintColor.R) / 100,
                (s1 * originalColor.G + strength * tintColor.G) / 100,
                (s1 * originalColor.B + strength * tintColor.B) / 100);
        }

        private void tintBitmapButton_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = new Bitmap("lena.jpg");
            bitmap.SetEachPixelColour(
                (point, color) =>
                {
                    return TintColor(color, Color.Blue, 50);
                });
            pictureBox.Image = bitmap;
        }

Which produces this Lena;

lenaTint1

Tinting an image – method 2

This method converts the pixel to black and white before mixing in the tint color – so that nothing of the original image color remains;

        private void tint2BitmapButton_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = new Bitmap("lena.jpg");
            Color targetColor = Color.SpringGreen;
            bitmap.SetEachPixelColour(
                (point, color) =>
                {
                    double luminence = ((color.R * 30 + color.G * 59 + color.B * 11) / 100.0) / 255.0;
                    return
                        Color.FromArgb(
                            Convert.ToByte(targetColor.R * luminence),
                            Convert.ToByte(targetColor.G * luminence),
                            Convert.ToByte(targetColor.B * luminence));

                });
            pictureBox.Image = bitmap;
        }

Which produces this Lena;

lenaTint2

Compare two images – the naive way

In a later blog post, I’ll talk about robust ways of comparing images, but here’s a naive approach for comparing two images of the same size. It computes the summed “colour distance” between the images.

        private double CompareBitmaps(Bitmap firstBitmap, Bitmap secondBitmap)
        {
            if (firstBitmap.Width != secondBitmap.Width || firstBitmap.Height != secondBitmap.Height)
            {
                return 1;
            }

            double difference = 0;
            firstBitmap.ExecuteForEachPixel(
                point =>
                {
                    Color firstColor = firstBitmap.GetPixel(point.X, point.Y);
                    Color secondColor = secondBitmap.GetPixel(point.X, point.Y);
                    difference += Math.Abs(secondColor.R / 255.0 - firstColor.R / 255.0);
                    difference += Math.Abs(secondColor.G / 255.0 - firstColor.G / 255.0);
                    difference += Math.Abs(secondColor.B / 255.0 - firstColor.B / 255.0);
                });

            // Normalize the difference so it's not size dependent
            difference /= (firstBitmap.Width * firstBitmap.Height);

            return difference;
        }

Comparing identical images returns 1, comparing totally de-similar images returns 0.