Posts tagged LINQ
Dynamically building ‘Or’ Expressions in LINQ
Feb 12th
One common question on Stackoverflow concerns the creation of a LINQ expression that logically Ors together a set of predicates. The need stated is to be able to build such an expression dynamically. Creating the ‘And’ version is easy, you simply stack multiple ‘.Where‘ clauses onto an expression as you add each predicate. You can’t do the same for ‘Or’. The common responses are ‘use LINQKit’ or ‘use Dynamic LINQ’. LINQKit however adds the unfortunate ‘.AsExpandable()’ into the expression which can cause problems in some circumstances, and Dynamic LINQ is not strongly-typed so doesn’t survive renaming operations. Neither answer is ideal.
But, there is another way, using a bit of Expression tree manipulation you can build an ‘Or‘ expression dynamically while staying strongly-typed. The code below achieves this.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class ExpressionBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<T> Compose<T>(this Expression<T> first,
Expression<T> second,
Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters
.Select((f, i) => new { f, s = second.Parameters[i] })
.ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from
// the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from
// the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.Or);
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(
Dictionary<ParameterExpression,
ParameterExpression> map)
{
this.map = map??new Dictionary<ParameterExpression,ParameterExpression>();
}
public static Expression ReplaceParameters(
Dictionary<ParameterExpression,
ParameterExpression> map,
Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
}
NB Some of the ideas in this case from other blog posts, I can’t find them right now but if part of this was your idea I’d be happy to add a link to your blog.
Home Automation with Voxeo (VoxML/Voice XML)
Jan 28th
One of the features of my home automation system is the ability to call the house up and speak to it to ask it to do things. To enable this I’m using Voxeo and their excellent developer program which gives me an inbound phone number and the ability to host a VoiceXML application with voice recognition and text to speech.
Using Linq-to-XML I can build the required VoiceXML hand it off to Voxeo when they request it during an incoming call, e.g.
XDocument doc = new XDocument(
new XDeclaration(“1.0″, “utf-8″, “yes”),
new XComment(“Voice XML feed”),
new XElement(“vxml”, new XAttribute(“version”, “2.1″),
new XElement(“form”, new XAttribute(“id”, “MainMenu”),
new XElement(“field”, new XAttribute(“name”, “room”), hereswhatIdid,
new XElement(“grammar”, new XAttribute(“type”, “text/gsl”),
new XCData(
“[" +
@" [ " + WholeHouseGrammar() + " ]” +
“]”)),
new XElement(“noinput”, “I did not hear anything. Please try again”, new XElement(“reprompt”)),
new XElement(“nomatch”, “I did not recognize that command. Please try again”, new XElement(“reprompt”))), …
The ‘WholeHouseGrammar’ is generated on the fly by examining the hierarchy of objects in the house so it includes every room, light, sprinkler, …
At present the house only understands on/off commands but in the future I hope to hook it up to the natural language engine so that the grammar is instead constructed dynamically from every sentence that the house understands today when you chat to it.
So currently you say things like ‘Front right sprinklers on’ when you notice the lawn needs an extra cycle as you drive out the house. In the future you’ll be able to ask it more complex questions like ‘who called last week on friday after 4pm?’ which is a question it can already handle using the chat interface.
Tip: getting the index in a foreeach statement
Dec 10th
Using LINQ you can easily get at the index in a foreach statement.
List x = new List() {"a", "b", "c"};
var augmented = x.Select((item, index) => new { item = s, index = index });
foreach (var d in augmented)
{
Console.WriteLine(d.item + " " + d.index);
}
Console.ReadKey();
a 0
b 1
c 2
Linq’s missing link
Mar 3rd
I came across this library today and it rocks. http://www.albahari.com/nutshell/linqkit.aspx
Without this library trying to pass Linq Expressions into Where clauses on Linq to Entities just didn’t work beyond some very simple (trivial) examples.
With this library I can now combine multiple filter function expressions and pass them to my query, and it works as intended:
Expression<func<datetime,bool>> contains = ts.Contains;
var query = from caller in dataContext.CallerIDLogs.AsExpandable()
where contains.Invoke(caller.DateTime)
select caller;