Using Expression Trees in C#.
-----------------------------
Even though there are lots of articles regarding Expression Tree, I would like to explain with an example where expression trees were really useful for me.
Here is my requirement. I have to write a library file which will be consumed by others. I would be having List<MovieData> object.
MovieData class contains the follwing propertis.
int? MovieId;
string Classification,
string Genre,
int? Rating,
int? ReleaseDate,
string Title
I have to write a search functionality. So, my function signature will be as showing below.
public List<MovieData> SearchMovie(int? movieId, string classification, string genre, int? rating, int? releaseDate, string title)
{
//
}
The user while giving hte input can give either 1 or more input's or none. There are lots of ways ot complete the functionality. But I found using
Expression trees I was able to complete the requriement very easily.
public List<MovieData> SearchMovie(int? movieId, string classification, string genre, int? rating, int? releaseDate, string title)
{
if (movieCollection == null)
return null;
var param = Expression.Parameter(typeof(MovieData), "t");
Expression body = null;
Expression<Func<MovieData, bool>> lambda = null;
List<MovieData> resultSet = null;
if(rating.HasValue)
body = Expression.Equal(Expression.PropertyOrField(param, "_rating"), Expression.Constant(rating));
if(!string.IsNullOrEmpty(title))
body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_title"), Expression.Constant(title)));
if(!string.IsNullOrEmpty(classification))
body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_classification"), Expression.Constant(classification)));
if(!string.IsNullOrEmpty( genre))
body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_genre"), Expression.Constant(genre)));
if(releaseDate.HasValue)
body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_releaseDate"), Expression.Constant(releaseDate)));
if(movieId.HasValue)
body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_movieId"), Expression.Constant(movieId)));
if (body != null)
{
lambda = Expression.Lambda<Func<MovieData, bool>>(body, param);
resultSet = movieCollection.Where(lambda.Compile()).ToList();
}
else
resultSet = movieCollection;
return resultSet;
}
public List<MovieData> SearchMovie(int? movieId, string classification, string genre, int? rating, int? releaseDate, string title) { if (movieCollection == null) return null; var param = Expression.Parameter(typeof(MovieData), "t"); Expression body = null; Expression<Func<MovieData, bool>> lambda = null; List<MovieData> resultSet = null; if(rating.HasValue) body = Expression.Equal(Expression.PropertyOrField(param, "_rating"), Expression.Constant(rating)); if(!string.IsNullOrEmpty(title)) body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_title"), Expression.Constant(title))); if(!string.IsNullOrEmpty(classification)) body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_classification"), Expression.Constant(classification))); if(!string.IsNullOrEmpty( genre)) body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_genre"), Expression.Constant(genre))); if(releaseDate.HasValue) body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_releaseDate"), Expression.Constant(releaseDate))); if(movieId.HasValue) body = Expression.AndAlso(body, Expression.Equal(Expression.PropertyOrField(param, "_movieId"), Expression.Constant(movieId))); if (body != null) { lambda = Expression.Lambda<Func<MovieData, bool>>(body, param); resultSet = movieCollection.Where(lambda.Compile()).ToList(); } else resultSet = movieCollection; return resultSet; }
It is seen that I am generating the expression body only if the values are not null and finally I am using the expression generated on the collection.
The same thing can be achived even using filters. But each input has to be checked for null nad the filter has to be applied on hte collection each and every
time.
Thanks,
Sanjay.