Friday 19 October 2018

C# - IEnumerable++ Linq, Lambdas, AsQueryable

So in the previous post I wrote a Linq query against the IEnumerable enabled Customers class. In that post I showed the Non-Public members and wanted to replicate them. I am glad to give here some code with replicates the original Line query.

It turns out according to this SO answer that there are two ways of using LINQ expressions, you have to use either Lambda expression or SQL-Like expression

The Original "SQL" Linq Query
Customers custs = new Customers();
var query = from Customer c in custs where c.Country != "Mexico" select new { c.CustomerId, c.CustomerName };
The Linq Query Re-Expressed With Lambdas
Customers custs = new Customers();
var query2 = custs.AsQueryable().Where(c => c.Country != "Mexico").Select((c) => new { c.CustomerId, c.CustomerName });

Inspecting the variable query shows the same Non-Public members are shown in previous post.

AsQueryable

So I named this series of posts as IEnumerable++. It seems IQueryable++ may now seem more appropriate. The hop from IEnumerable to IQueryable is achieved by the Queryable.AsQueryable method. That is the magic method that takes us away from the SQL-like syntax to the Lambda syntax.

Links

Latest Source

So this source code is evolving, I have separated and commented out the Orders class for tidiness. It remains a console program. I will need the Orders class when I introduce joins.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using System.Dynamic;
using System.Linq.Dynamic;   // Install-Package 'System.Linq.Dynamic' NuGet
using System.Linq.Expressions;

namespace ConsoleEnumTut01
{
    class Program
    {
        static void Main(string[] args)
        {
            Customers custs = new Customers();
            var query = from Customer c in custs where c.Country != "Mexico" select new { c.CustomerId, c.CustomerName };

            foreach (var customer in query)
            {
                Console.WriteLine(customer.GetType().ToString());
                Console.WriteLine(customer);
            }
            LinqWithLambdas();
        }

        static void LinqWithLambdas()
        {
            Customers custs = new Customers();
            var query2 = custs.AsQueryable().Where(c => c.Country != "Mexico").Select((c) => new { c.CustomerId, c.CustomerName });

            foreach (var customer in query2)
            {
                Console.WriteLine(customer.GetType().ToString());
                Console.WriteLine(customer);
            }
        }
    }

    class Customer
    {
        public int CustomerId { get; set; } // key field, unique identifier
        public string CustomerName { get; set; }
        public string ContactName { get; set; }
        public string Country { get; set; }
        public override string ToString() { return String.Format("{0} {1}", CustomerId, CustomerName); /* simple for now */ }
    }

    class Customers : IEnumerable<Customer>, IEnumerator<Customer>
    {
        // private members
        List<Customer> _customers;
        int _cursor;

        // constructors
        public Customers()
        {
            // delegate to Factory
            _customers = CustomersListFactory.CreateCustomers();
            _cursor = -1;
        }

        //
        // Interfaces explicitly implemented
        //

        // IEnumerable<>
        IEnumerator<Customer> IEnumerable<Customer>.GetEnumerator()
        {
            return this;
        }

        // IEnumerable
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }


        // IEnumerator, IEnumerator<>
        Customer IEnumerator<Customer>.Current => _customers[_cursor];

        object IEnumerator.Current => _customers[_cursor];

        bool IEnumerator.MoveNext()
        {
            _cursor++;
            return (_cursor < _customers.Count);
        }

        void IEnumerator.Reset()
        {
            _cursor = -1;
        }

        // IDisposable
        void IDisposable.Dispose()
        {

        }
    }

    static class CustomersListFactory
    {
        public static List<Customer> CreateCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { CustomerId = 1, CustomerName = "Big Corp", ContactName = "Mandy", Country = "USA" });
            customers.Add(new Customer { CustomerId = 2, CustomerName = "Medium Corp", ContactName = "Bob", Country = "Canada" });
            customers.Add(new Customer { CustomerId = 3, CustomerName = "Small Corp", ContactName = "Jose", Country = "Mexico" });
            return customers;
        }
    }

    /*
    class Order
    {
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
        public override string ToString() { return String.Format("{0} {1} {2}", OrderId, CustomerId, OrderDate);  }
    }





    static class OrdersListFactory
    {
        public static List<Order> CreateOrders()
        {
            List<Order> orders = new List<Order>();
            orders.Add(new Order { OrderId = 420, CustomerId = 2, OrderDate = new DateTime(2018, 10, 10) });
            orders.Add(new Order { OrderId = 421, CustomerId = 3, OrderDate = new DateTime(2018, 10, 11) });
            orders.Add(new Order { OrderId = 422, CustomerId = 1, OrderDate = new DateTime(2018, 10, 12) });
            orders.Add(new Order { OrderId = 423, CustomerId = 2, OrderDate = new DateTime(2018, 10, 13) });
            return orders;
        }
    }

    class Orders : IEnumerable<Order>, IEnumerator<Order>
    {
        // private members
        List<Order> _orders;
        int _cursor;

        // constructors
        public Orders()
        {
            // delegate to Factory
            _orders = OrdersListFactory.CreateOrders();
            _cursor = -1;
        }

        //
        // Interfaces explicitly implemented
        //

        // IEnumerable<>
        IEnumerator<Order> IEnumerable<Order>.GetEnumerator()
        {
            return this;
        }

        // IEnumerable
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }


        // IEnumerator, IEnumerator<>
        Order IEnumerator<Order>.Current => _orders[_cursor];

        object IEnumerator.Current => _orders[_cursor];

        bool IEnumerator.MoveNext()
        {
            _cursor++;
            return (_cursor < _orders.Count);
        }

        void IEnumerator.Reset()
        {
            _cursor = -1;
        }

        // IDisposable
        void IDisposable.Dispose()
        {

        }
    }
*/
}

C# - IEnumerable++ Our First Linq Query

So I want to start running some Linq queries against our simple classes which support IEnumerable (and thus IEnumerator). I want to start poking around at the types that are created on our behalf by LINQ expressions.

So following on from the code in previous post where I built two classes Customers, and Orders to poke around how to implement IEnumerable (even though I ended up delegating to IList<>), I can now write a LINQ query, so here is the console program's Main() method

    class Program
    {
        static void Main(string[] args)
        {
            Customers custs = new Customers();
            var query = from Customer c in custs where c.Country != "Mexico" select new { c.CustomerId, c.CustomerName };

            foreach (var customer in query)
            {
                Console.WriteLine(customer.GetType().ToString());
                Console.WriteLine(customer);
            }
        }
    }

So this compiles but let's inspect what is compiled on our behalf, here is a screenshot of the query variable

The screenshot is not copy and pastable so I give in plain text what I see because I want to Google on these terms ...

query        {Sytem.Linq.Enumerable.WhereSelectEnumerableIterator<ConsoleEnumTut01.Customer, <>f_AnonymousType0<int,string> >

query, Non-Public members
current      { CustomerId = 1, CustomerName = "Big Corp" }
enumerator   {ConsoleEnumTut01.Customers}
predicate    {Method = { Boolean <Main> b__0_0(ConsoleEnumTut01.Customer)}}
selector     {Method = {<>f__AnonymousType0`2[System.Int32,System.String] <Main>b__0_1(ConsoleEnumTut01.Customer)}}
source       {ConsoleEnumTut01.Customers}

Above, in the Non-Public members <Main> refers to the method Main(), if you move the code to a separate procedure called, e.g. Foo(), then the <Main> will change to <Foo>. Also, we can see the select new clause is compiled to an anonymous type though I cannot says what the 0`2 suffix naming convention represents. Lastly, one can see b__0_0 and b__0_1 looks like it is incrementing; if moved to a separate method Foo() then they become b__1_0 and b__1_1 so I'm guessing the increments are there to avoid some name class in some name space somewhere. Lots to investigate there.

Why delve to such a low level? Well, I'm interested to see if we actually need these Linq expressions or if they can be compiled separately from strings etc. and be parameterized. Dynamic Linq does this though I am (as yet) unclear as to how far I can take this.

Thursday 18 October 2018

C# - IEnumerable++ Introduction

I am very curious about C# and its LINQ technology. My first guesses are that LINQ Is based on IEnumerable. I'm starting a series of posts based on IEnumerable and technologies based thereupon, hence IEnumerable++.

I'm placing some beginner code here because I want to revisit IEnumerable from the ground up. This is because it is (I believe) a key interface in the advanced topic of Linq. Here is a screenshot of the System.Linq.Enumerable metadata showing the prevalence of IEnumerable.

So in the screenshot one can see plenty of SQL keywords such as Select and OrderBy, off-screen are other keywords such as Join, GroupBy, Count, Distinct, Union, Where. It is clear to me that the beginner topic IEnumerable is a key interface worth knowing inside out because it will assist in understanding the advanced topic of System.Linq.Enumerable. I will work from beginner topics through to advanced in a series of posts.

So some of these posts may look too elementary but it is a question of dotting i's and crossing t's for a fuller understanding.

IEnumerable drives ForEach

So most people know IEnumerable as being that which drives foreach statement. Here is some code which shows an automatic implementation by virtue of the List<> class as well as a manual implementation explicitly implementing IEnumerable and IEnumerator. The code that follows is intended for a console .NET Framework project.

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleEnumTut01
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Customer> customers = ListFactory.CreateCustomers();

            foreach (var customer in customers)
            {
                Console.WriteLine(customer);
            }

            Customers customers2 = new Customers();
            foreach (var customer2 in customers2)
            {
                Console.WriteLine(customer2);
            }
        }
    }

    class Customer
    {
        public int CustomerId { get; set; } // key field, unique identifier
        public string CustomerName { get; set; }
        public string ContactName { get; set; }
        public string Country { get; set; }
        public override string ToString() { return String.Format("{0} {1}", CustomerId, CustomerName); /* simple for now */ }
    }

    class Customers : IEnumerable<Customer>, IEnumerator<Customer>
    {
        // private members
        List<Customer> _customers;
        int _cursor;

        // constructors
        public Customers()
        {
            // delegate to Factory
            _customers = ListFactory.CreateCustomers();
            _cursor = -1;
        }

        //
        // Interfaces explicitly implemented
        //

        // IEnumerable<>
        IEnumerator<Customer> IEnumerable<Customer>.GetEnumerator()
        {
            return this;
        }

        // IEnumerable
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }


        // IEnumerator, IEnumerator<>
        Customer IEnumerator<Customer>.Current => _customers[_cursor];

        object IEnumerator.Current => _customers[_cursor];

        bool IEnumerator.MoveNext()
        {
            _cursor++;
            return (_cursor < _customers.Count);
        }

        void IEnumerator.Reset()
        {
            _cursor = -1;
        }

        // IDisposable
        void IDisposable.Dispose()
        {

        }
    }

    class Order
    {
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public DateTime OrderDate { get; set; }
    }

    static class ListFactory
    {
        public static List<Customer> CreateCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { CustomerId = 1, CustomerName = "Big Corp", ContactName = "Mandy", Country = "USA" });
            customers.Add(new Customer { CustomerId = 2, CustomerName = "Medium Corp", ContactName = "Bob", Country = "Canada" });
            customers.Add(new Customer { CustomerId = 3, CustomerName = "Small Corp", ContactName = "Jose", Country = "Mexico" });
            return customers;
        }

        public static List<Order> CreateOrders()
        {
            List<Order> orders = new List<Order>();
            orders.Add(new Order { OrderId = 420, CustomerId = 2, OrderDate = new DateTime(2018, 10, 10) });
            orders.Add(new Order { OrderId = 421, CustomerId = 3, OrderDate = new DateTime(2018, 10, 11) });
            orders.Add(new Order { OrderId = 422, CustomerId = 1, OrderDate = new DateTime(2018, 10, 12) });
            orders.Add(new Order { OrderId = 423, CustomerId = 2, OrderDate = new DateTime(2018, 10, 13) });
            return orders;
        }
    }
}

I want to start running some LINQ queries, see next post.

Links