Is there a way I can dynamically define a Predicat

2020-07-20 04:55发布

This is probably a stupid question, but here goes. I would like to be able to dynamically construct a predicate < T > from a string parsed from a database VARCHAR column, or any string, for that matter. For example, say the column in the database contained the following string:

return e.SomeStringProperty.Contains("foo");

These code/string values would be stored in the database knowing what the possible properties of the generic "e" is, and knowing that they had to return a boolean. Then, in a magical, wonderful, fantasy world, the code could execute without knowing what the predicate was, like:

string predicateCode = GetCodeFromDatabase();
var allItems = new List<SomeObject>{....};
var filteredItems = allItems.FindAll(delegate(SomeObject e) { predicateCode });

or Lambda-ized:

var filteredItems = allItems.FindAll(e => [predicateCode]);

I know it can probably never be this simple, but is there a way, maybe using Reflection.Emit, to create the delegate code dynamically from text and give it to the FindAll < T > (or any other anonymous/extension) method?

4条回答
Root(大扎)
2楼-- · 2020-07-20 05:04

Check out the Dynamic Linq project it does all this and more!

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Great for simple stuff like user selected orderby's or where clauses

查看更多
孤傲高冷的网名
3楼-- · 2020-07-20 05:06

The C# and VB compilers are available from within the .NET Framework:

C# CodeDom Provider

Be aware though, that this way you end up with a separate assembly (which can only be unloaded if it's in a separate AppDomain). This approach is only feasible if you can compile all the predicates you are going to need at once. Otherwise there is too much overhead involved.

System.Reflection.Emit is a great API for dynamically emitting code for the CLR. It is, however, a bit cumbersome to use and you must learn CIL.

LINQ expression trees are an easy to use back-end (compilation to CIL) but you would have to write your own parser.

I suggest you have a look at one of the "dynamic languages" that run on the CLR (or DLR) such as IronPython. It's the most efficient way to implement this feature, if you ask me.

查看更多
小情绪 Triste *
4楼-- · 2020-07-20 05:09

I stepped off the dynamic linq because it's limited in ways I want to search a collection, unless you prove me wrong.

My filter needs to be: in a list of orders, filter the list so that I have only the orders with in the collection of items in that order, an item with the name "coca cola".

So that will result to a method of: orders.Findall(o => o.Items.Exists(i => i.Name == "coca cola"))

In dynamic linq I didn't find any way to do that, so I started with CodeDomProvicer. I created a new Type with a method which contains my dynamically built FindAll Method:

public static IList Filter(list, searchString)
{
   // this will by dynamically built code
   return orders.Findall(o => o.Items.Exists(i => i.Name == "coca cola"));
}

when I try to build this assembly:

CompilerResults results = provider.CompileAssemblyFromSource(parameters, sb.ToString());

I'm getting the error:

Invalid expression term ">"

Why isn't the compiler able to compile the predicate?

查看更多
Fickle 薄情
5楼-- · 2020-07-20 05:16

It is possible using emit, but you'd be building your own parser.

EDIT

I remember that in ScottGu's PDC keynote, he showed a feature using the CLI version of the .net framework that resembled Ruby's eval, but I can't find a URL that can corroborate this. I'm making this a commnity wiki so that anyone who has a good link can add it.

查看更多
登录 后发表回答