Showing posts with label Linq. Show all posts
Showing posts with label Linq. Show all posts

Saturday, September 26, 2009

IEnumberable, IQueryable , Lambda expression - part2

I have seen such following piece of code written by a developer from a client.

interface IContactRepository { IEnumberable<Contact> GetSomeContacts(); } class ContactRepository : IContactRepository { public IEnumerable<Contact> GetSomeContacts() { //query is linq to sql query object IQueryable<Contact> query = ... return query; } }

Is it a better choice to using IEnumerable<T> instead of IQueryable<T>. I guess his concerns is that, if the interface is too specific, first this may give client more functionality than is required, second this may limit the server's choice of implementation. In lots case, this concern is right, we should give client the only functionality which client needs, nothing less and nothing more, and server should has more freedom to implement.

interface IPerson { void Eat(); void Sleep(); } interface ISales : IPerson { void Sell(); } interface ITeacher : IPerson { void Teache(); } class Service { //Unappropriate // public ISales GetPerson() // { // return ... // } //better public IPerson GetPerson() { return ... } }

Firstly, if the method return a ISales, First client will have one extra unnecessary method Sell. Secondly If the client only needs a IPerson, and the contract says client needs a IWorker, this will limit server's ability to serve the client, for example, server can not return a ITeacher.

Is this design guideline also applicable to the case of IContactRepository.

public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable {} public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } }

First the the IQuerable<T> interface does give user more functionality than the IEnunumerable<T>, but these members are read only, and client can not use them directly for query. Because the query functionality comes from the static method in Enumerable and Queryable, but not the IQuerable<T>, and IEnumeralbe<T>, from the client's perspective, Two interfaces works identically. Secondly, the interface does limit limit server's implementation choice, because server cannot return a IEnumberable<T> . Initially, I thought I can implement easily a empty IQueryable<T> that wrap a IEnumberable<T>. It turns out to be even easier. Because the Enumerable already implement an static method AsQueryable() for you, the Linq team in Microsoft already expect this is a common use case. So all you need to do is call the method can you IEnumberable&lgt;T> will become IQueryable<T>. like the following.

int[] intEnumerable = { 1, 2, 3 , 5}; IQueryable intQuery = intEnumerable.AsQueryable().Where( number => number > 2); foreach (var item in intQuery) { Console.WriteLine(item); } Console.WriteLine(intQuery.GetType().ToString()); //System.Linq.EnumerableQuery`1[System.Int32] //code decompiled by reflector ParameterExpression CS$0$0000; IQueryable intQuery = new int[] { 1, 2, 3, 5 }.AsQueryable<int>().Where<int>(Expression.Lambda<Func<int, bool>>(Expression.GreaterThan(CS$0$0000 = Expression.Parameter(typeof(int), "number"), Expression.Constant(2, typeof(int))), new ParameterExpression[] { CS$0$0000 })); foreach (object item in intQuery) { Console.WriteLine(item); } Console.WriteLine(intQuery.GetType().ToString());

So a it seems be a better to replace IEnumberable<T> with IQueryable<T>. As for as the interface concerns, the replacement does not give client any exactly same query experience and it is more difficult to implement. A great benefit of this replacement is the performance, using IEnumberable<T> will be much slower than IQuerable<T>. Consider the following code, the Where method for IQueryable<T> will treat the lambda expression as expression tree and query will be executed at server side which is much faster, while the IEnumerable<T> will treat the lambda expression as delegate and query will be executed at client side, which will be slower. Consider the following code.

var thisContact = contaceRepository. GetSomeContacts().Where( ctc => ctc.Id = 1).First();

Linq provide us a new way to design our domain model. In the post Extending the World, author says

Typically for a given problem, a programmer is accustomed to building up a solution until it finally meets the requirements. Now, it is possible to extend the world to meet the solution instead of solely just building up until we get to it. That library doesn't provide what you need, just extend the library to meet your needs.

It is very important to build extensible domain model by taking the advantage of IQueryable<T> interface. Using IEnumberable<T> only will hit the performance very seriously. The only pitfall to user IQueryable<T> is that user may send unnecessary complex to the server, but this can be resolved by designing the method so that only appropriate IQueryable<T> is returned, for example return GetSome instead of GetAll. Another solution is adding a view model which return a IEnumberable<T>

IEnumberable, IQueryable , Lambda expression - part1

When we type the following code

IEnumerable<int> intEnumerable = null; var q1 = intEnumerable.Where( x => x > 10);

we know that Where method is not part of the IEnumberable<T> interface or IEnumberable interface, it comes from extension method of Enumerable, which is static class and it has no inheritance relation With IEnumerable or IEnumberable<T>. The power of Linq-To-Object does not come from IEnumberable or IEnumberable or its implemenation, it comes from the extension method. Let's take a look what does the extension method do? Using Reflector we get the following source code.

public static class Enumerable { public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } if (source is Iterator<TSource>) { return ((Iterator<TSource>) source).Where(predicate); } if (source is TSource[]) { return new WhereArrayIterator<TSource>((TSource[]) source, predicate); } if (source is List<TSource>) { return new WhereListIterator<TSource>((List<TSource>) source, predicate); } return new WhereEnumerableIterator<TSource>(source, predicate); } }

We can see there , the delegate passed in to the method is the code that does the filtering.

IQueryable inherit from IEnumerable. But what extra value does the IQueryable bring. Let's take a look of the following code. and the code it generated by c# compiler.

public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable {} public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } }

It does not tell too much? Let's move on an querable example and decomplie to see what it does.

IQueryable<int> intQuerable = null; var q2 = intQuerable.Where(x => x > 10); // decomplied by reflector ParameterExpression CS$0$0000; IQueryable<int> q2 = intQuerable.Where<int>(Expression.Lambda<Func<int, bool>>(Expression.GreaterThan(CS$0$0000 = Expression.Parameter(typeof(int), "x"), Expression.Constant(10, typeof(int))), new ParameterExpression[] { CS$0$0000 }));

From this example, we can see that the Lamda Expression is not converted to a delegate, but to an expression tree. But why the extension method Enumerable.Where(IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) is not used? It turns out that, the c# compiler pick a more a suitable extension from Queryable. Here is the code from Reflector.

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } return source.Provider.CreateQuery<TSource>(Expression.Call(null, ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(new Type[] { typeof(TSource) }), new Expression[] { source.Expression, Expression.Quote(predicate) })); }

Unlike the Enumerable.Where methhod, this method does not have a delegate to do the filtering. And also the expression can not do the filtering either, it is the IQuerable.Provider which does the filtering. The provider takes the expression tree and does filtering later by converting expression tree to provider specific algorithm like TSQL.

IEumberable<T> is very easy to implement, in fact all the collection they are IEnumberable<T*gt;. Iterator makes it even easier. So there is not such thing as implementing a IEnumberableProvider, because the delegate does the query. But to implement IQueryable is more difficult, because expression does not query. It is IQueryProvider does the job. You need to implement IQuerableProvider

public interface IQueryProvider { IQueryable CreateQuery(Expression expression); IQueryable<TElement> CreateQuery<TElement>(Expression expression); object Execute(Expression expression); TResult Execute<TResult>(Expression expression); }