How to simplify an expression when converting it to a string? - c#

I need to pass an expression from a WinForms client to a WebApi. I have the following expression:
var results = somelist.Select(p => p.Id).ToList<int>();
Expression<Func<MyObj, bool>> myexp = x => results.Contains(x.Id);
I then simply did:
var str = myexp.Body.ToString();
However, in this particular example, the expression body looks like this:
value(MyApp.MyForm+<>c__DisplayClass41_0).results.Contains(x.Id)
Which obviously will not work when translating back the string to an expression server-side.
Is there a way to reduce, compile, whatever the expression in a better way? Or should I use 3rd party solutions like Remote.Linq or Serialize.Linq?

It depends on what you need to do with the expression on the server side.
If you really only need a string representation you might want to implement an ExpressionVisitor. However, this may require quite some effort, depending the kind of expressions you need to support.
In case you want to convert back to a proper expression tree and execute the expression on server side, it's definitely worth the have a look at Remote.Linq.

Related

how to convert lambda expressions into json string

I have two applications. One application saves options and configurations down as JSON and the other reads the JSON and performs it's task based on the fields in the JSON. Now I want to filter a list that is in application-2. How can I pass how I want the list to be filtered into a string to be stored in JSON and then reinterpreted by application-2?
Is there anyway to serialize linq/lambda expressions and deserialize them? Or is there a better approach like creating a class that contains some filterable options like equal-to, not-equal-to, greater-than, less-than, contains, etc?
Unfortunately there is no way to serialize and serialize a lamda expression in c#, because it is make in compile time.
The Lamda after the compilation generates a function and the compiler call this function when the lamda expression is used.
You have one option, but is not easy :) Yoy have to store a c# code in json file, and the application-2 will read it, parse it, compile it, and execute it.
But itt will be a complete assembly (like one class) not only one lamdba expression.
If you use :net framrwork here is an example:
https://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
If you use .Net Core, teh ypu have to use roslyn: https://josephwoodward.co.uk/2016/12/in-memory-c-sharp-compilation-using-roslyn
I hope it helps
regrads
I found for another solution for this problem. You can store and revert an Expression from string! :)
The only need, the two module (or two program in your case) must be the known the same type.
Sample code:
var discountFilter = "album => album.Quantity > 0";
var options = ScriptOptions.Default.AddReferences(typeof(Album).Assembly);
Func<Album, bool> discountFilterExpression =
await CSharpScript.EvaluateAsync<Func<Album, bool>>(discountFilter, options);
var discountedAlbums = albums.Where(discountFilterExpression);
Regrads
gy
If you want to filter javascript arrays in pure JSON, you can use Jpath and Json.Net
For example:
var token = JToken.Parse("json string here")
var tokens = token.SelectTokens("$.YourJsonArray[?(#.Property == something)]")

Regular Expression matching using Lambda Expressions

I am trying to implement a wildcard search Functionlity for (*,?) using LINQ to SQL. As of now, I want to try it using Regular expression as the code we write will be short and easily manageable. Here is what I have
string kw=_keyword.Replace("*",".*").Replace("?",".");
var predicate = PredicateBuilder.True<DAL.RequestAttribute>();
Regex reg=new Regex("^"+kw+"$");
predicate=predicate &&(reg.IsMatch(ra=>ra.AttributeValue));
So, here it gives a compilation error as "Cannot convert lambda expression to type 'string' because it is not a delegate type"
Though some workarounds if I make it compile and run, I get this runtime Error
"Method 'Boolean IsMatch(System.String)' has no supported translation to SQL."
So, I have two Questions here
1. Am I thinking in right lanes to implement my wildcard using Regular Expressions? if not, which is more efficient way to do this?
2. How to resolve this error .
Thanks
You could mimic SQL's LIKE operator by using SqlMethods.Like: https://msdn.microsoft.com/en-us/library/system.data.linq.sqlclient.sqlmethods.like%28v=vs.110%29.aspx.
Just be sure to use the appropriate wildcards/tokens: https://msdn.microsoft.com/en-us/library/ms179859.aspx.
Update:
You cannot use regular expressions with simple SQL. Since you are essentially building a SQL statement via LINQ, the same rule applies. Though, it's still not quite clear where you are tapping into LINQ with the sample code you've provided.
I would typically expect to see something like the following:
var results =
from Something in SomeLinqContext
where SqlMethods.Like(Something.Value, kw);
After some research I found an answer to my question. Thanks to Ventaur for the Suggestion. the solution is on similar lines but just a bit different. PFB the code for it
string kw=_keyword.Replace("*","%").Replace("?","_");
var predicate = PredicateBuilder.True<DAL.RequestAttribute>();
predicate = (ra => SqlMethods.Like(ra.AttributeValue, kw) && <Any other boolean conditions>
Therefore it boils down to how to make an expression out of SQLMethods.like method using our predicate builder class.

How to convert a search string to a boolean condition?

I have a search criteria stored in a string:
string Searchstr = "(r.Value.Contains("PwC") || (r.Value.Contains("Canadian") && r.Value.Contains("thrive"))) || (r.Value.Contains("Banana") && r.Value.Contains("Gayle"))"
I want to use this in a If statement to check the values:
if(searchstr)
{
then do this....
}
but the if should have a searchstr as boolean.
How to convert this to boolean?
EDIT: The requirement is to give search criteria dynamically in a text box in the following format - "PwC OR (Canadian AND thrive)".
Which will be used to search an XML file.
Therefore I have loaded an XML file and want to have a Where condition in LINQ for which I need to use Dynamic LINQ but string is not allowed in that and also I have some braces to deal with.
Thinking of that I have taken the resultset from the XML(The tag value which i need to search)
var selectedBook = from r in document.Root.Descendants("Archives").Elements("Headline").Elements("Para")
select r;
and would ideally like to try something like:
var query=selectedbook.Where(searchstr)
OR
if(searchstr){....then do this}
You will need to do a bit of work to make this happen, but it is possible.
You should have a look at the dynamic LINQ library. This allows you to specify LINQ conditions (and other clauses) as strings and execute them just like LINQ operators.
Start with the explanation on ScottGu's blog and follow the links:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
I'm assuming the string is going to reference only a specific set of objects (r or r.Value in this case, for example - or anything else you want, as long as you know it beforehand). If this is the case, then:
Create a delegate that takes the objects (that may be referenced) as parameters
and returns a bool, as you want.
Programmatically write a small C# source file in memory that defines the query
as the body of a method (with a fixed name, preferably) that conforms to the delegate specified above.
Use the CSharpCodeProvider class to compile an assembly
with your custom function that returns the bool you want.
Run the dynamically written and compiled code from your main program.
Well as you may guess it is not going to be straight forward but at the same time it is not as hard a problem as it seems
You can perform a few steps to get what you want:
Get the search expression as input (for e.g. "PwC OR (Canadian AND thrive)")
Write an extension method on XElement that returns true and takes the search criteria as input. You will then be able to use
var selectedBook = from r in
document.Root.Descendants("Archives").Elements("Headline").Elements("Para")
where r.SatisfiesCriteria(searchCriteria)
select r;
Write a parser class that parses searchCritera and stores it in parsed format. (for e.g. you can convert it into postfix notation). This is quite easy and you can use standard algorithm for this. For your purpose OR, AND will be operators and PwC etc. will be operands. Parenthesis will get removed as part of parsing.
Now simply invoke this parser from with in your extension method and then evaluate the postfix expression you get. This again can be done through standard stack based evaluation. Infact it would be better if you parse the criteria once and then only evaluate in where. While evaluating you need to replace the operands with r.Value.Contains
It seems like a good scenario for http://scriptcs.net/

Parsing "DateTime.Now"?

I need to translate strings like this:
"DateTime.Now.AddDays(-7)"
into their equivalent expressions.
I'm only interested in the DateTime class. Is there anything built into .Net that'll help me do this, or do I just need to write my own little parser?
You can employ FLEE to do the expression parsing for you. The below code is tested and working in Silverlight (I believe in full C#, it may have a slightly different syntax around creating the expression, but it might work exactly like this anyway)
ExpressionContext context = new ExpressionContext();
//Tell FLEE to expect a DateTime result; if the expression evaluates otherwise,
//throws an ExpressionCompileException when compiling the expression
context.Options.ResultType = typeof(DateTime);
//Instruct FLEE to expose the `DateTime` static members and have
//them accessible via "DateTime".
//This mimics the same exact C# syntax to access `DateTime.Now`
context.Imports.AddType(typeof(DateTime), "DateTime");
//Parse the expression, naturally the string would come from your data source
IDynamicExpression expression = ExpressionFactory.CreateDynamic("DateTime.Now.AddDays(-7)", context);
//I believe there's a syntax in full C# that lets you evaluate this
//with a generic flag, but in this build, I only have it return type
//`Object` so we cast (it does return a `DateTime` though)
DateTime date = (DateTime)expression.Evaluate();
Console.WriteLine(date); //January 25th (7 days ago for me!)

Lambda expression as query for API?

Just started looking at the OData support for the WebAPI and for now it seems like there is alot left to do until the "querying-support" becomes truly interesting.. and thats sort of where this idea were born.. would it be possible some how to send a lambda expression as a querystring and then parse that and run it against an IEnumerable and then return the value?
The whole problem is the expression parsing and how to actually execute the parsed expression against the object.. Im quite unsure about how to do such a thing.. any ideas?.. or is there any place where I can read more about this?
Thanks in advance!
What I understood from your interest is to write your own LINQ parser. check this out: Invent your own dynamic LINQ parser
Also have a look at the discussion happening over implementation of Like operator support for OData here.

Categories