Using a CSharpSyntaxRewriter I'd like to determine if a a particular BinaryExpression is an Artihmetic expression. Is there a simpler way to determine this than to code snippet below.
private static bool IsArithmeticOperator(BinaryExpressionSyntax node)
{
return node.IsKind(SyntaxKind.AddExpression) ||
node.IsKind(SyntaxKind.MultiplyExpression) ||
node.IsKind(SyntaxKind.DivideExpression) ||
node.IsKind(SyntaxKind.SubtractExpression) ||
node.IsKind(SyntaxKind.ModuloExpression);
}
Just feels a little clunky.
I am not sure this is possible, but there is something in the enum that maybe can help you,
the arithmetic expression are in order inside the enum SyntaxKind except ModuloExpression which you can check separately.
maybe other SyntaxKind in this range will also be good for your needs.
AddExpression = 307,
SubtractExpression = 308,
MultiplyExpression = 309,
DivideExpression = 310,
IntegerDivideExpression = 311,
ExponentiateExpression = 314,
LeftShiftExpression = 315,
RightShiftExpression = 316,
ConcatenateExpression = 317,
ModuloExpression = 318,
So you can do something like this :
private static bool IsArithmeticOperator(BinaryExpressionSyntax node)
{
SyntaxKind expressionKind = node.Kind();
return (expressionKind >= SyntaxKind.AddExpression && expressionKind <= SyntaxKind.DivideExpression)
|| expressionKind == SyntaxKind.ModuloExpression;
}
Update
This will work only for Microsoft.CodeAnalysis.VisualBasic
and wont work for Microsoft.CodeAnalysis.CSharp
Related
I've opted to implement the System.Linq.Dynamic namespace into my project where I rely on dynamically invoking LINQ expressions from a string against my underlying objects. This allows for highly configurable criteria at the data level.
string expression = "x.Client == 100 && x.Insurers.Any(it == 2 || it == 3)";
var x = new MyObject() { Client = 100, Insurers = new int[] { 1, 2 }};
var p = Expression.Parameter(typeof(MyObject), "x");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, expression);
bool result = e.Compile().DynamicInvoke(x); // True = condition met
My question is how do I dynamically identify the number of conditions each string expression contains so that I can give a weight to each expression and choose the one with the highest weight when overlapping occurs. Regex can work, but there must be something more efficient and practical such as an expression tree.
Ex.:
x.Client == 100 // Conditions = 1
x.Client == 100 && x.Insurers.Any(it == 3) // Conditions = 2
x.Client == 100 && x.Insurers.Any(it == 2 || it == 3) // Conditions = 3
I'm not familiar with the System.Linq.Dynamic library, but assuming it produces normal, strongly typed Expression trees you can use an ExpressionVisitor.
This one counts the number of boolean logical operations like &&:
int CountConditions(Expression expr)
{
var visitor = new CountBinaryOpsVisitor();
visitor.Visit(expr);
return visitor.BinaryOperationCount + 1;
}
class CountBinaryOpsVisitor : ExpressionVisitor
{
public int BinaryOperationCount { get; private set; }
protected override Expression VisitBinary(BinaryExpression node)
{
switch (node.NodeType)
{
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.ExclusiveOr:
// Don't count bitwise integer operations, if they are even supported?
if (node.Left.Type == typeof(bool))
BinaryOperationCount++;
break;
}
return base.VisitBinary(node);
}
}
An alternative approach would be to count the number of comparison operators (==, >= etc.), but I think that would need more complex code to handle boolean expressions like x.BooleanProp or x.Insurers.Any().
This implementation doesn't currently count conditional expressions (x ? y : z). Not sure how you would factor those into the number of conditions, especially when nested.
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
First off, sorry if the title isn't clear or descriptive; I didn't know what to write exactly.
I'm wondering if there is a better way to do this operation:
bool result = variable1.innerValue.level2.innerValue == 1 ||
variable1.innerValue.level2.innerValue == 2 ||
variable1.innerValue.level2.innerValue == 3;
We can't write something like:
bool result = variable1.innerValue.level2.innerValue == (1 || 2 || 3);
This will give a syntax error.
Any ideas?
You could use a collection as placeholder and Enumerable.Contains:
if(new[]{1, 2, 3}.Contains(variable1.innerValue.level2.innerValue))
{
}
or, for what it's worth, this extension:
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
which enables you to write this:
if(variable1.innerValue.level2.innerValue.In(1, 2, 3))
{
}
What are your favorite extension methods for C#? (codeplex.com/extensionoverflow)
In this case. you can do Enumerable.Range(1, 3).Contains(variable1.innerValue.level2.innerValue).
using System.Linq;
...
bool result = new[] {1, 2, 3}.Contains(variable1.innerValue.level2.innerValue);
var listToCheck = new int[]{1,2,3};
var innerValue = variable1.innerValue.level2.innerValue;
bool result = listToCheck.Contains(innerValue);
Honestly, the first thing that comes to my mind is the good old Introduce Explaining Variable refactoring, which not only reduces the duplication but also makes your code more self-explanatory:
var innerValue = variable1.innerValue.level2.innerValue;
bool result = innerValue == 1 || innerValue == 2 || innerValue == 3;
How about
(new List<int>(){1,2,3}).Exists(i=>i == variable1.innerValue.level2.innerValue)
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)));
}
I have the following class:
public class Test
{
public string Text { get; set; }
public int Number { get; set; }
}
And I'm creating and Expression tree of type Expression<Func<Test, bool>> on this class. When I do it like this:
Expression<Func<Test, bool>> predicate1 = x => x.Text.Length > 5 && x.Number > 0;
I get the following debug view:
.Lambda #Lambda1<System.Func`2[NHLinqTest.Test,System.Boolean]>(NHLinqTest.Test $x) {
($x.Text).Length > 5 && $x.Number > 0
}
note: there's a && for and-operation.
When I do it like this:
var y = Expression.Parameter(typeof(Test));
var predicate2 = Expression.And(
Expression.GreaterThan(
Expression.Property(Expression.Property(y, "Text"), "Length"),
Expression.Constant(5)),
Expression.GreaterThan(
Expression.Property(y, "Number"),
Expression.Constant(0)));
I get the following debug view:
($var1.Text).Length > 5 & $var1.Number > 0
Note: there's & for and-operation. Why do I get & in the second case? How to modify predicate2 to get && instead of &?
Thanks in advance!
Because it is & - i.e. bitwise / non-short-circuiting "and". For && you want Expression.AndAlso.
See also Expression.Or (|) vs Expression.OrElse (||).
Also, note that Expression != C# - it is language independent, so you might also see some cases where you don't get back (visually) what you would expect from C#.
Compare Expression.And:
Creates a BinaryExpression that represents a bitwise AND operation.
and Expression.AndAlso:
Creates a BinaryExpression that represents a conditional AND operation that evaluates the second operand only if the first operand evaluates to true.
And then compare that to your knowledge of the & and && operators.
The "&" operator and Expression.And represent a bitwise and. The "&&" operator and Expression.AndAlso represent a logical (and short-cutting) and operator.