简体   繁体   中英

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 need 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 (eg Name, Age) should call "GetValue". Any suggestions?

Obviously the where statement is completely up to the user and is not fixed.

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.

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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM