Dynamic LINQ on a generic object (without any hard-coded properties)
I have a generic object which uses a dictionary to store the properties:
class MyObject
{
Dictionary<string, object> Properties = new Dictionary<string, object>();
internal GetValue(string name) { return Properties[name]; }
internal SetValue(string name, object value) { Properties[name] = value; }
}
MyObject obj1 = New MyObject();
obj1.SetValue("Name", "John");
obj1.SetValue("Age", 23);
MyObject obj2 = New MyObject();
obj2.SetValue("Name", "Mary");
obj2.SetValue("Age", 24);
List<MyObject> ObjList = new List<MyObject>();
ObjList.Add(obj1);
ObjList.Add(obj2);
Now we ne开发者_开发知识库ed to query the ObjList to find certain entries. Dynamic LINQ (Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)) seems to be perfect, but from what I can see it requires that the object have pre-defined properties.
We want to do queries like:
ObjList.Where("Name == 'Mary' || Age < 24");
Any token (e.g. Name, Age) should call "GetValue". Any suggestions?
Obviously the where statement is completely up to the user and is not fixed.
In C# 4.0 you could have your MyObject
implement the IDynamicMetaDataProvider
interface so that property tokens get resolved to GetValue() and SetValue() respectively. Dynamic LINQ should then work as expected.
See this post for an example
The source for the Dynamic LINQ extension method Where clause is:
public static IQueryable Where(this IQueryable source, string predicate, params object[] values) {
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Where",
new Type[] { source.ElementType },
source.Expression, Expression.Quote(lambda)));
}
The complicated part is the DynamicExpression.ParseLambda bit. A very quick look through the source shows that the parsing code includes a "ParseMemberAccess" function which seems to suggest that you might be able to do something like:
ObjList.Where("GetValue('Name') == 'Mary' || GetValue('Age') < 24");
And, if the parser doesn't currently allow that, you could easily extend it so that it does.
精彩评论