Reputation: 4816
Consider this code:
static void Main(string[] args)
{
var persons = new List<Person>
{
new Person("Name1", "Surname1", 30),
new Person("Name2", "Surname2", 20),
new Person("Name3", "Surname3", 10)
};
var filters = new List<Func<Person, bool>>
{
p => p.Age > 10,
p => p.Surname.Contains("2")
};
var personsFiltered = new List<Person>(persons);
foreach (var filter in filters)
{
personsFiltered = personsFiltered.Where(filter).ToList();
}
foreach (var person in personsFiltered)
{
Console.WriteLine(person);
}
Console.ReadKey();
}
}
class Person
{
public string Name { get; private set; }
public string Surname { get; private set; }
public int Age { get; private set; }
public Person(string name, string surname, int age)
{
Name = name;
Surname = surname;
Age = age;
}
public override string ToString()
{
return String.Format("Name:{0}, Surname:{1}, Age:{2}", Name, Surname, Age);
}
}
Is it possible to pass filters as string parameters, so that the user could create custom filters? For example, the filters
list in my example would initially be empty and the user would provide strings "p => p.Age > 10" and "p => p.Surname.Contains(\"2")"?
Upvotes: 2
Views: 545
Reputation: 1575
You have two options to allow the user to write code for your application : A scripting engine and dynamic compilation.
LUA
You could integrate a scripting engine like Lua (I found that very easy) : /technical/game-programming/using-lua-with-c-r2275">http://www.gamedev.net/page/resources//technical/game-programming/using-lua-with-c-r2275
You need to create a Lua environment, set the variables to be used by the user's script, then read the variables from that environment. I built a partly scripted printing template engine using this method and it worked perfectly. LuaInterface for C# is very intuitive and simple.
DYNAMIC COMPILATION
Another option is to implement dynamic compilation (a little more trouble, but more powerful) : http://www.codeproject.com/KB/dotnet/DynamicCompileAndRun.aspx
You need to create a framework class and concatenate a string to include the user's script inside a class that implements a certain interface. Something like :
class ClientScript : IScriptFramework {
public override String Method(Object object) {
return %CLIENT_CODE%;
}
}
Assuming IScriptFramework declares Method, you can store an isntance of this class into a IScriptFramework and call Method without any reflection. Just store this code in a resource, generate the final source code by replacing %CLIENT_CODE% with the actual code (like object.ToString()) and compiling that in memory as described in the post I linked.
I used dynamic compilation for a testing framework and it works pretty well, although the syntax is more strict than a script engine like Lua.
EDIT : Viacheslav Smityukh is right, there is a framework that does the hard job of dynamically compiling LINQ queries for you. I read about it a while back, but I didn't think about before I saw his comment. It may be the easiest way to go for you : http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Upvotes: 2