Optimizing LINQ expressions with anonymous types and methods

Advanced LINQ techniques

  • Share

When LINQ was announced in .NET framework 3.5 I was a bit skeptic because it look a bit odd to me on the first look. Writing queries in C#, just did not look right to me.

Anyway, not all the things introduced in .NET had long life. Remember J# and F#? I do not know know any person who actually uses these languages or any larger project coded in these two.

However LINQ is an exception from these two. As soon as I started using it my code start shrinking, much easier to maintain and a lot faster to write. I discovered LINQ :)

Indeed LINQ is really powerful, but "with power comes responsibility", especially if you are applying LINQ when reading some external resource like database (EntittyFramework, LINQ to SQL) or XML (LINQ to XML).

Anonymous types

One thing where I find it really useful is also when returning result in JSON format in WebAPI.

As demands for features of your service grow, you have to return different types and serialized class instances for every service method/action you create. In the end, you might end up with a pile of POCO classes used only for returning result from your business logic to your facade.

To avoid that there is an ability to create POCO class instances on the fly. This way, you can, while querying EntityFramework or XML document, create your view models

    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<int, string> list = new Dictionary<int, string>();
            list.Add(1, "Banana");
            list.Add(2, "Kiwi");
            list.Add(3, "Orange");
            list.Add(4, "Apple");

            Console.WriteLine(
                new JavaScriptSerializer().Serialize(
                    list.Select(l => new { id = l.Key, name = l.Value.ToUpper() })
                ));

            Console.ReadLine();
        }
    }
    

If you take this sample code and just paste it in your console application, it will work because it does not depend on any class in project. POCO class structure is generated on the fly. This means on the same set of data you can just apply different query to get different structure in the result.

Anonymous methods

Lets say you have scenario where you need to select user node from XML document and transform it to custom structure in JSON for each item in your result set.

        static void Main(string[] args)
        {
            Dictionary<int, string> list = new Dictionary<int, string>();
            list.Add(1, "Banana");
            list.Add(2, "Kiwi");
            list.Add(3, "Orange");
            list.Add(4, "Apple");

            Console.WriteLine(
                new JavaScriptSerializer().Serialize(
                    list.Select(l => new
                    {
                        id = l.Key,
                        name = l.Value.ToUpper(),
                        stock = XDocument.Parse(new StreamReader(HttpWebRequest.Create("http://fruit-service.com").GetResponse().GetResponseStream()).ReadToEnd()).Element("fruits").Elements("fruit").Where(e => e.Attribute("id").Value == l.Key.ToString()).FirstOrDefault().Element("stock"),
                        quality = XDocument.Parse(new StreamReader(HttpWebRequest.Create("http://fruit-service.com").GetResponse().GetResponseStream()).ReadToEnd()).Element("fruits").Elements("fruit").Where(e => e.Attribute("id").Value == l.Key.ToString()).FirstOrDefault().Element("quality"),
                        arrival = XDocument.Parse(new StreamReader(HttpWebRequest.Create("http://fruit-service.com").GetResponse().GetResponseStream()).ReadToEnd()).Element("fruits").Elements("fruit").Where(e => e.Attribute("id").Value == l.Key.ToString()).FirstOrDefault().Element("arrival")
                    })
                ));

            Console.ReadLine();
        }
    

This means, you will query XML document for each item in query result set which is not so nice, considering that performance of LINQ to XML drop on large XML documents. Even worse if that XML structure is provide by some external service (other WebAPI). This means you need to select users XML element from document and keep it while you are working with item from result set and reload it for the next item.

        static void Main(string[] args)
        {
            Dictionary<int, string> list = new Dictionary<int, string>();
            list.Add(1, "Banana");
            list.Add(2, "Kiwi");
            list.Add(3, "Orange");
            list.Add(4, "Apple");

            Console.WriteLine(
                new JavaScriptSerializer().Serialize(
                    list.Select(l =>
                    {
                        XElement serviceResult = XDocument.Parse(new StreamReader(HttpWebRequest.Create("http://fruit-service.com").GetResponse().GetResponseStream()).ReadToEnd()).Element("fruits").Elements("fruit").Where(e => e.Attribute("id").Value == l.Key.ToString()).FirstOrDefault();
                        return new
                    {
                        id = l.Key,
                        name = l.Value.ToUpper(),
                        stock = serviceResult.Element("stock"),
                        quality = serviceResult.Element("quality"),
                        arrival = serviceResult.Element("arrival")
                    };
                    })

                ));

            Console.ReadLine();
        }
    

References

  • Share

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.

Comments for this article

comments powered by Disqus