I have a scenario in which I am saving my "if" conditions in database as a string. For example:
String condition = "(([age] >= 28) && ([nationality] == 'US'))";
OR
String condition = "([age] >= 28)";
Now, I want to evaluate that the user has input the condition syntactically correct. These are example of incorrect syntax:
String condition = "(([age] >= 28) && ([nationality] == 'US')"; //Missed ')' bracket
String condition = "[age] >= 28)"; //Missed Opening bracket '('
Like we have in Evaluate Query Expression. Might be Expression tress can be helpful. But how? Need help in this regard.
Take a look at NCalc. It's a framework for evaluating mathematical expressions.
When the expression has a syntax error, the evaluation will throw an EvaluationException.
try
{
new Expression("(3 + 2").Evaluate();
}
catch(EvaluationException e)
{
Console.WriteLine("Error catched: " + e.Message);
}
Though, you can also detect syntax errors before the evaluation by using the HasErrors() method.
Expression e = new Expression("a + b * (");
if(e.HasErrors())
{
Console.WriteLine(e.Error);
}
Visual studio doesn't really know what the strings represent so to my knowledge there is no parsing done within the strings themselves.
Typically when programming with C# and using sql, you'd try to do as much of the calculations as possible in C# itself (if it's feasible select the whole table then deal with the result using C#).
If the database is really slow which is quite often the case, it may be useful writing a SQL Builder class to deal with the hardcoded strings.
If you use neither of these methods, unfortunately the best you can really hope for is runtime exceptions (which isn't optimal for obvious reasons).
EDIT:
It seems a SelectQueryBuilder library already exists for the second scenario I suggested.
I found this solution
evaluate an arithmetic expression stored in a string (C#)
SOLUTION:
string conditiontext = "(([age] >= 28) && ([nationality] == \"US\"))";
conditiontext = conditiontext.Replace("[age]", 32)
.Replace("[nationality]","US");
/*VsaEngine*/
var engine = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
/** Result will be either true or false based on evaluation string*/
var result = Microsoft.JScript.Eval.JScriptEvaluate(conditiontext, engine);
[Note: This interface is deprecated. But it evaluates any arithmetic expressions and c# expressions]
You could use System.Data and its DataTable.Compute() method.
Here is the code:
public bool CheckCondition()
{
// parameters
(string name, object value)[] variables =new (string name, object value)[1];
variables[0].name = "age";
variables[0].value = 28;
variables[1].name = "nationality";
variables[1].value = "US";
string conditions = "(([age] >= 28) && ([nationality] == 'US'))";
conditions.Replace("[", "").Replace("]", "").Replace("&&", "AND").Replace("||", "OR");
using DataTable table = new DataTable();
foreach (var (name, value) in variables)
table.Columns.Add(name, value is null ? typeof(object) : value.GetType());
table.Rows.Add();
foreach (var (name, value) in variables)
table.Rows[0][name] = value;
table.Columns.Add("_Result", typeof(double)).Expression = conditions
?? throw new ArgumentNullException(nameof(conditions));
return (bool)(Convert.ChangeType(table.Compute($"Min(_Result)", null), typeof(bool)));
}
Related
In the below code, I am repeating the same code twice except one change. If there is a way to write the same in single line then it would be great.
The only changes I made is Obsc and zp based on the if..else statement.
var zp = __Services.GetValue("Z", Order.Code);
var St="";
if(sp.Label != null)
{
var Obsc = _Services.GetValue("Z", sp.Label);
St= string.Format(Obsc, .......,userProfile.DisplayName());
}
else
{
St = string.Format(zp, ......., userProfile.DisplayName());
}
Are you happy with something like this?
var code = sp.Label is null
? Order.Code
: sp.Label;
var zpOrObsc = service.GetValue("Z", code); // please use a valid variable name
var st = string.Format(zpOrObsc, ......, userProfile.DisplayName());
St = string.Format(_Services.GetValue("Z", sp.Label ?? Order.Code), ......., userProfile.DisplayName());
Make a variable to determine which parameter value you want to call GetValue with. You only need to call GetValue once and string.Format once.
var whateverTheSecondParamForGetValueIs = Order.Code;
if (sp.Label != null) {
whateverTheSecondParamForGetValueIs = sp.Label;
}
var zp = _Services.GetValue("Z", Order.Code);
var St = string.Format(zp, ......., userProfile.DisplayName());
No, this isn't a "single line", but I don't see the appeal in that. To me, this is much more readable than any ternary operator.
I'm also going to say that these variable names need quite an improvement. They don't convey any meaning.
The ternary (*) operator, also known as the "conditional operator" is basically a short-hand for "if then else " and is written like so:
result = condition ? trueValue : falseValue;
It is not comparable to an actual if ... else ... statement as it is an expression and must provide a value.
See its documentation in the C# language reference for full details: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator.
*) So called because it is the only operator that takes 3 arguments. Compare with "binary operator" and "unary operator".
I was reading through some code on Github recently and i came across the following line,
if (((tmp = rx.IndexOf("<")) >= 0) && (rx.IndexOf(">") > tmp ))
specifically the
(tmp = rx.IndexOf("<") >= 0)
And the immediate use of the tmp variable in a comparison in the same line in the next part of the if statement
(rx.IndexOf(">") > tmp )
in which a variable is being set by a string,indexOf() method, and then the 'assignment statement itself' is being evaluated with a greater-or-equal-to equality operator.
At first i thought this was a typo, but on evaluating the code via a simple console app, i found it to be valid, and a great shortcut.
The question is "What is the technical term for this?" as i could find no explanation in various C# help sites.
An example console app to demonstrate how the statement was used.
public static void Main()
{
// first test - the actual code I found in gitHub
int tmp;
int tmp2;
string rx = " < test>";
// the below line is the subject of the question.
if (((tmp = rx.IndexOf("<")) >= 0) && (rx.IndexOf(">") > tmp )){
Console.WriteLine("The Close brace is after the opening brace!");
}
// additional test
int r;
Console.WriteLine(r = 25 + 3);
Console.WriteLine(r);
// and another
int w = -1;
Console.WriteLine(" The index of '<' is greater than 0 : " + _
((w = rx.IndexOf("<")) > 0).ToString() + _
" and the value of w is " + w.ToString());
}
The output of the above code is below.
Again , I understand the code works, I would like to know what is this called technically?
The Close brace is after the opening brace!
28
28
The index of '<' is greater than 0 : True and the value of w is 2
There is no "technical term".
It's an assignment, and a assignment can act as expression or a statement.
It's a statement that has a value; Or an Expression where the result value can be ignored. (Unlike x+y, the Result is not allowed to be ignored)
It's the same as the prefix and postfix operators i++;
It will look less like "inline" in a line like x = y = z;
However, it's not often used, cause it's less readable, as you just proofed.
And in your case, assigning a value and using the value in the same expression tree
highly depends on evaluation order, which is well defined, but who knows it by heart ?
This style of writing will safe you a line of code (by making one line longer)
but it will never save you any operation, hence not cause any performance.
So Read it, Understand it, but better don't use it frequent.
This is just a consequence of assignment being an expression. It is defined in the C# specification:
7.17.1 Simple Assignment
The = operator is called the simple assignment operator.
The result of a simple assignment expression is the value assigned to
the left operand. The result has the same type as the left operand and
is always classified as a value.
So the value of
tmp = rx.IndexOf("<")
is the value assigned to tmp which is rx.IndexOf("<"). This value is then compared to 0 in the outer expression.
I am looking for a way to get a boolean value from a string.
I have a string, stored in a database, that is a condition to be tested with.
suppose the string = "[number] < 10000"
In my code I then plan to replace [number] with a actual number so the string would become "100 < 10000".
Is there a simple way to evaluate this string to a boolean.
In this case it would be False.
Another example: "[number] > 100 && [number] < 1000"
If number would be 200, the evaluation would be True.
What if I add code to this condition, like "if ([number] > 100 && [number] < 1000) { return true;} else {return false;}"
If there a simple way to get the return value from this string with code?
You can make use of DynamicExpression class, it is available in this nuget package. It can evaluate expressions on the fly.
Below is an example,
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda(
new System.Linq.Expressions.ParameterExpression[] { },
typeof(bool),
"100 > 1000",
new object[] { });
var compiledDelegate = expression.Compile();
var result = compiledDelegate.DynamicInvoke(null);
The result will be false as the provided expression "100 > 1000" is false.
If you need more control, you have to create expressions depending upon dynamic strings representing logical operations. For example, I have taken your first case of "[number]<1000" You can try below:
static void Main(string[] args)
{
string code = "[number] < 10000".Replace("[number]", "100");
string[] operands = code.Split('<');
var comparison = Expression.LessThan(
Expression.Constant(operands[0]),
Expression.Constant(operands[1]));
var lambda = Expression.Lambda<Func<bool>>(comparison).Compile();
bool result = lambda();
}
Or Alternatively you can use existing libraries or nuget packages for doing same thing in a more simpler way (under hood they do same though):
string code = "[number] < 10000".Replace("[number]", "100");
func = ExpressionParser.Compile<Func<bool>>(code);
bool result = func()
It makes use of Lambda parser as shown here
Lets say i have
int a = 1;
int b = 2;
string exp = "b > a";
and i want to evaluate the string expression with those variables
if(exp.SomeKindOfParseOrCast())
{
//here be magic
}
Is it possible in any simple way?
Nope, not in C# - these are parameter names, and thus are compile time values, and this expression parsing you are describing is done in runtime - the computer doesn't know the name of the parameters while it's being evaluated. Instead, you could do something a little more strict, like an expression parser - implement your own way to parse string expressions.
Very very simplified:
if(exp.Equals("b > a"))
{
if(b>a)
// do what you do if b is bigger than a
else
// do what you do with a wrong expression
}
else if (exp.Equals("a > b")
{
if(a>b)
// do what you do if a is bigger than b
else
// do what you do with a wrong expression
}
else if (exp.Equals("a = b")
{
if(a==b)
// do what you do if a is equal to b
else
// do what you do with a wrong expression
}
else
// do what you do with a badly formatted expression
if you would like to take this a step forward, you can cut spaces, make sure the expression is lowercase, etc. - there's many examples around, I personally like this one.
Is it possible in any simple way?
No, in C# this is not possible in a simple way like it were in languages such as JavaScript with its eval function. Anyway, you'd have to provide bindings of in-expression parameters to actual values.
You can use Roslyn.
Here is an example of how to compile and run your own code in runtime.
Disclaimer: I'm the owner of the project Eval Expression.NET
This library is very easy to use and allow to evaluate and compile almost all the C# language.
// For single evaluation
var value1 = Eval.Execute<bool>("b > a", new { a = 1, b = 2 });
// For many evaluation
var compiled = Eval.Compile<Func<int, int, bool>>("b > a", "a", "b");
var value2 = compiled(1, 2);
let assume we have an array like this:
var caps = new[] { "1512x", "001xx", "27058", "201xx", "4756x" };
(original array is huge and come from another linq query)
What I need is to create a LINQ statement accepting a value and tries to match with one of the values on the foreseen array.
For example if I use "15121" I need to match the "1512x" value on the array and return it.
Obviously, if I use "27058" it finds the exact match and simply return it.
Is it possible in LINQ?
The "wildcard" char on the array is "x", but I can change it.
Thanks in advance!
Valerio
You can use regular expressions:
var value = "15121";
var caps = new[] { "1512x", "001xx", "27058", "201xx", "4756x" };
var match = caps
.FirstOrDefault(c => new Regex("^" + c.Replace("x", "[0-9]") + "$").IsMatch(value));
if (match != null)
Console.WriteLine("{0} matches {1}", value, match);
The "pattern" 001xx is converted into the regular expression ^001[0-9][0-9]$ and so on. Then the first matching regular expressions is found.
But if the caps is huge it might not perform so well because each regular expression has to be compiled and converted into a state machine until a match is found.
Assuming you have a predicate method, something like this (or something equivalent using Regex, as described in another answer):
static bool Match(string pattern, string exact)
{
if(pattern.Length != exact.Length) return false;
for(var i = 0; i < pattern.Length; i++)
if(pattern[i] != exact[i] && pattern[i] != 'x')
return false;
return true;
}
Then the LINQ query can look like this:
var found = caps.Single(x => Match(x, yourSearch));