OK, I have a code (see below):
void M1()
{
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" +
(i - 1).ToString() +
"CheckBox", true);
if ((carr != null) && (carr.Length > 0))
{
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = i % 2 == 0 ? true : false; // or any other value
}
}
}
I don't like iteration with using Controls.Find method. Can I replace it with something easier ?
PS: all the NumberXCheckBox (X>=0 and X<=8) presented on the form.
LINQ enabled, .net 3.5, Visual studio 2008.
Instead of searching by name, can you wrap your CheckBox controls in a container that means you can just iterate through the controls in the container?
I would encourage you to introduce a field in your type to keep references to your checkboxes (an array, a list, a dictionary -- you choose.) This way you'll no longer need to use this non-typed and somewhat ugly find-control-by-key-method.
Anyway, if you're still in .NET 2.0 and prefer to use the Find method, you could simplify a little bit your loop:
for (var i = 0; i <= 8; i++)
{
var controls = Controls.Find("Number" + i + "CheckBox", true);
if (controls.Length > 0)
{
var checkBox = controls[0] as CheckBox;
if (checkBox != null)
checkBox.Checked = i%2 == 0;
}
}
The latest non-nullity test on checkbox can probably be omitted.
If you are using 3.5 or otherwise have LINQ available you could do the following
for ( int i = 0; i < 9; i++) {
var control = this.Controls
.Find(String.Format("Number{0}Checkbox", i))
.Cast<CheckBox>()
.FirstOrDefault();
if ( control != null ) {
control.Checked = (i % 2) != 0;
}
}
More linq-y
for (int i = 0; i < 10; i++) {
var c = (from CheckBox c in this.Controls.Find(String.Format(CultureInfo.InvariantCulture, "Number{0}CheckBox", i-1), true)
select c).FirstOrDefault();
if (c != null) {
c.Checked = i % 2 == 0 ? true : false;
}
}
Here's one without linq, but cleaned up the code a little bit.
for (int i = 1; i < 10; i++)
{
Control[] carr = this.Controls.Find("Number" + (i - 1) + "CheckBox", true);
if (carr.Length <= 0) continue;
CheckBox enableCB = carr[0] as CheckBox;
enableCB.Checked = (i % 2) == 0;
}
[Edit: added the Find(..) code to show why you don't have to check for null]
Here's the frameworks internal code for the Find function. I've added a couple of comments in it
public Control[] Find(string key, bool searchAllChildren)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
}
// Will always return an ArrayList with zero or more elements
ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
// Will always return an Array of zero or more elements
Control[] array = new Control[list.Count];
list.CopyTo(array, 0);
return array;
}
Related
I want to add the exact value of textbox into datagridview my problem is if i will add another item the last item I add will also change. Here is the print screen of sample problem..
1st try
2nd try
This is my code.
int n = dataGridView3.Rows.Add();
for (int j = 0; j < dataGridView3.RowCount; j++)
{
if (dataGridView3.Rows[j].Cells[1].Value != null && (textBox4.Text == dataGridView3.Rows[j].Cells[4].Value.ToString()))
{
MessageBox.Show("Item Already on List!");
dataGridView3.Rows.Remove(dataGridView3.Rows[n]);
return;
}
else
{
dataGridView3.Rows[j].Cells[1].Value = textBox43.Text;
dataGridView3.Rows[j].Cells[4].Value = textBox4.Text;
dataGridView3.Rows[j].Cells[2].Value = DateTime.Now.ToShortDateString();
dataGridView3.Rows[j].Cells[3].Value = dateTimePicker3.Text;
dataGridView3.FirstDisplayedScrollingRowIndex = n;
dataGridView3.CurrentCell = dataGridView3.Rows[n].Cells[0];
dataGridView3.Rows[n].Selected = true;
}
}
You are looping over the complete array and if it is not yet on the list it goes in to the else part of your if. In that block you assign the current entered values to your row, for every single row you already have.
To fix that I separated the Check for duplicates and the Add part more clearly.
Do notice that if you would have run this through the debugger and stepped on each line of your code (hitting F10 in Visual Studio) you would have spotted this bug easily. Have a look at the blog from Scott Guthrie (among others) http://weblogs.asp.net/scottgu/debugging-tips-with-visual-studio-2010
// check if we already added that one
for (int j = 0; j < dataGridView3.RowCount; j++)
{
if (dataGridView3.Rows[j].Cells[1].Value != null && (textBox4.Text == dataGridView3.Rows[j].Cells[4].Value.ToString()))
{
MessageBox.Show("Item Already on List!");
return;
}
}
// lets add it!
int n = dataGridView3.Rows.Add();
dataGridView3.Rows[n].Cells[1].Value = textBox43.Text;
dataGridView3.Rows[n].Cells[4].Value = textBox4.Text;
dataGridView3.Rows[n].Cells[2].Value = DateTime.Now.ToShortDateString();
dataGridView3.Rows[n].Cells[3].Value = dateTimePicker3.Text;
dataGridView3.FirstDisplayedScrollingRowIndex = n;
dataGridView3.CurrentCell = dataGridView3.Rows[n].Cells[0];
dataGridView3.Rows[n].Selected = true;
I have four arrays of equal length
I am using those arrays in foreach loops.
I am using four variables(i,j,k,l) to increment and to proceed
I am writing my code inside the four nested loops, that code should execute when i=0,j=0,k=,0,l=0
i=1,j=1,k=1,l=1
i=2,j=2,k=2,l=2
.....(depending on the array length)
Please suggest me the code for this required segment.
int i = 0, j = 0, k = 0, l = 0;
foreach (string fieldName in splitFieldnames)
{
i = 0;
foreach (string dataType in splitDatatypeNames)
{
j = 0;
foreach (string controlName in SplitControlNames)
{
k = 0;
foreach (string controlType in splitControlTypeNames)
{
if (i == j && j == k && k == l)
{
if (controlType == "textbox" && dataType == "string")
{
Response.Write("_Student." + fieldName + "= " + controlName + ".Text;");
l++;
break;
}
}
k++;
}
j++;
}
i++;
}
}
I think using LINQ would save you a lot of manual coding:
static void Main(string[] args)
{
var splitFieldnames = new string[] { "field1", "field2", "field3" };
var splitDatatypeNames = new string[] { "datatype1", "string", "string" };
var SplitControlNames = new string[] { "control1", "control2", "control3" };
var splitControlTypeNames = new string[] { "combobox", "textbox", "textbox"};
// this code can handle different sized arrays, but is based strictly
// on the size of the splitFieldnames array as the base.
var splitMerged = splitFieldnames.Select
((c, idx) =>
new
{
fieldName = c,
dataType = splitDatatypeNames.Length > idx ?
splitDatatypeNames[idx] : "",
controlName = SplitControlNames.Length > idx ?
SplitControlNames[idx] : "",
controlTypeName = splitControlTypeNames.Length > idx?
splitControlTypeNames[idx] : "",
});
foreach (var item in splitMerged
.Where(c => c.controlTypeName == "textbox" && c.dataType == "string"))
{
Response.Write("_Student." + item.fieldName + "= "
+ item.controlName + ".Text;");
}
The resulting output would be look like:
_Student.field2= control2.Text;
_Student.field3= control3.Text;
I hope that's what you're looking for, LOL...
I think that in this case a DataTable would be better than 4 arrays, and algorithm you require will be trivial with such data structure.
Use for instead of foreach
for (int i = 0; i < splitFieldnames.Length; i++)
{
string fieldName = splitFieldnames[i];
for (int j = 0; j < splitDatatypeNames.Length; j++)
{
string dataType = splitDatatypeNames[j];
for (int k = 0; k < SplitControlNames.Length; k++)
{
string controlName = SplitControlNames[k];
for (int l = 0; l < splitControlTypeNames.Length; l++)
{
string controlType = splitControlTypeNames[l];
if (i == j && j == k && k == l)
{
if (controlType == "textbox" && dataType == "string")
{
Response.Write("_Student." + fieldName + "= " + controlName + ".Text;");
break;
}
}
}
}
}
}
Note also that break will only break out of the innermost loop! Consider using a return statement instead.
UPDATE (in response to your edit):
The solution is simple, use only one index variable and only one for-loop instead of a lot of foreach-loops
for (int i = 0; i < splitFieldnames.Length; i++)
{
if (splitControlTypeNames[i] == "textbox" && splitDatatypeNames[i] == "string")
{
Response.Write("_Student." + splitFieldnames[i] + "= " + SplitControlNames[i] + ".Text;");
break;
}
}
(Assuming that you want to stop after the first match. If you want to output all string textboxes, drop the break statement.)
Ok, this code is really simple.. If you only need to show the data when i=j=k=l, then no need for any loop, or even for the existence of i,j,k,l.
If you can assure me that all this strings in whatever thing (a collection? an array? a dictionary?) are ordered, is ok.
If they are ordered, then throw away all the for each, and just access each one by position for all the controls you have in the collection that has the minimun.
If all this collection are not ordered, then this is totally uselles, since it will produce differents results on each run.
I will edit this answers with some code, once you can tell me if this is ordered or not.
EDIT:
First of all, you need to check what collection has the least items (since you can't go beyond that)... I don't know the types of this things (you didn't provide them), so let's assume they have a count property.
int minimun = splitFieldnames.count;
if (splitDatatypeNames.count < minimun)
minimun = splitDatatypeNames.count;
if (SplitControlNames.count < minimun)
minimun = SplitControlNames.count
if (splitControlTypeNames.count < minimun)
minimun = splitControlTypeNames.count
once you have the minimun value (since you can't go beyond that), just iterate on that and print whatever you want
for (int i = 0; i < minimun;i++)
{
if (splitControlTypeNames[i].tostring() == "textbox" && splitDatatypeNames[i].tostring() == "string")
{
//Response.Write("_Student." + fieldName + "= " + controlName + ".Text;");
//Also, a parametric string would be better ;)
string result = string.format("_Student.{0}= {1}.Text;",splitFieldnames[0].tostring(),SplitControlNames[0].tostring());
Response.Write(result);
l++;
}
}
I don't know the types, so I'm assuming that they have a tostring method an a count property
If what you are trying to accomplish is process the same index in the four arrays, just use one loop and use a counter to access the value in each array in that one loop:
foreach(string fieldName in SplitControlNames)
{
dataType = splitDatatypeNames[arrayPosition];
controlName = SplitControlNames[arrayPosition];
controlType = splitControlTypeNames[arrayPosition];
if (controlType == "textbox" && dataType == "string")
Response.Write("_Student." + fieldName + "= " + controlName + ".Text;");
arrayPosition++;
}
Or, create and populate a structure that has four values in it (fieldName, dataType, controlName, controlType) and have one array of that structure
I am needing an autoexpanding textbox like facebook has for it's status updates. I have code for it but for some reason it's not fully working correctly. It's updating the textbox and expanding it, but it is doing it way too soon. i am wanting it to expand when it gets to the end of the line. But it is doing it after 20 characters are entered! I have two different methods i have tried, they both do the same thing. Any suggestions on changing my code?
function sz(t) {
var therows = 0
var thetext = document.getElementById(t.id).value;
var newtext = thetext.split("\n");
therows += newtext.length
document.getElementById(t.id).rows = therows;
return false;
}
function sz(t)
{
a = t.value.split('\n');
b = 1;
for (x = 0; x < a.length; x++)
{
if (a[x].length >= t.cols)
{
b += Math.floor(a[x].length / t.cols);
}
}
b += a.length;
if (b > t.rows)
{
t.rows = b;
}
}
Check out this fiddle.
I think your problem was using txtbox.id rather than just passing the id.
I have a function that retrieves a list of device names and stores then in a variable. Then the next step is to get info using 1 device name per line and keep going till the loop is complete.
String text = "";
String errors = "";
for (int i = 0; i < collection.Result.Count; i++)
{
deviceNames += collection.Result[i].DeviceName + Environment.NewLine;
getvirtuals.Location = deviceNames;
var virtuals = client.GetKnownVirtuals(getvirtuals, LtmKeyType.VirtualAddressPort);
if (virtuals.Result == null)
{
i++;
getvirtuals.Location = deviceNames;
for (int v = 0; v < virtuals.Result.Count; v++)
{
try
{
LtmKey virtualKey = new LtmKey();
virtualKey.Location = virtuals.Result[v].Location;
virtualKey.LocationType = virtuals.Result[v].LocationType;
virtualKey.Key = virtuals.Result[v].Key;
virtualKey.KeyType = LtmKeyType.VirtualAddressPort;
virtualKey.AdminGroup = admingroupComboBox.Text;
var memberStatus = client.GetMemberStatus(virtualKey);
for (int j = 0; j < memberStatus.Result.Count; j++)
{
VirtualMemberStatus status = memberStatus.Result[j];
text += String.Format("{5},{4},{0},{1},{2},{3}" + Environment.NewLine, status.Member.Address, status.Member.Port, status.EffectiveStatus, status.DesiredStatus, virtualKey.Key.Replace(":", ","), DateTime.UtcNow);
toolStripProgressBar1.PerformStep();
}
}
catch
{
errors += String.Format("{0} Error Code: 2, Error occurred, check device name (case senstive) and admin group. This error may also occur due to connection loss, try again." + Environment.NewLine, DateTime.UtcNow);
}
}
this.allResultsBox.Text = text;
getallstatusButton.Enabled = true;
}
}
The problem that I am running into is that if virtuals is null the tool crashes, instead what I want to do is if virtuals = null I want to move onto the next item from the list. I have tried a if statement but it is not working the way planned, it still comes back as null.
Well this seems like a problem to start with:
if (virtuals.Result == null)
{
i++;
getvirtuals.Location = deviceNames;
for (int v = 0; v < virtuals.Result.Count; v++)
...
If virtuals.Result is null, how do you expect virtuals.Result.Count to work? I suspect you meant:
if (virtuals.Result != null)
However, I suspect you really just want:
// Keep going with the next iteration of the for loop
if (virtuals == null || virtuals.Results == null)
{
continue;
}
If all you want is to go to the next loop iteration if virtuals is null then you want
if (virtuals == null) continue;
How about just inserting:
if(virtuals == null)
continue;
right after the line
var virtuals = client.GetKnownVirtuals(getvirtuals, LtmKeyType.VirtualAddressPort);
Have you tried changing the line:
if (virtuals.Result == null)
to:
if ((virtuals != null) && (virtuals.Result != null))
If this doesn't solve your issue, then you need to indicate what the additional errors are.
if (virtuals.Result == null)
make this
if (virtuals == null)
This question already has answers here:
Is it possible to compile and execute new code at runtime in .NET?
(15 answers)
Closed 9 years ago.
Is there a function the .NET framework that can evaluate a numeric expression contained in a string and return the result? F.e.:
string mystring = "3*(2+4)";
int result = EvaluateExpression(mystring);
Console.Writeln(result); // Outputs 18
Is there a standard framework function that you can replace my EvaluateExpression method with?
If you want to evaluate a string expression use the below code snippet.
using System.Data;
DataTable dt = new DataTable();
var v = dt.Compute("3 * (2+4)","");
Using the compiler to do implies memory leaks as the generated assemblies are loaded and never released. It's also less performant than using a real expression interpreter. For this purpose you can use Ncalc which is an open-source framework with this solely intent. You can also define your own variables and custom functions if the ones already included aren't enough.
Example:
Expression e = new Expression("2 + 3 * 5");
Debug.Assert(17 == e.Evaluate());
Try this:
static double Evaluate(string expression) {
var loDataTable = new DataTable();
var loDataColumn = new DataColumn("Eval", typeof (double), expression);
loDataTable.Columns.Add(loDataColumn);
loDataTable.Rows.Add(0);
return (double) (loDataTable.Rows[0]["Eval"]);
}
You could look at "XpathNavigator.Evaluate" I have used this to process mathematical expressions for my GridView and it works fine for me.
Here is the code I used for my program:
public static double Evaluate(string expression)
{
return (double)new System.Xml.XPath.XPathDocument
(new StringReader("<r/>")).CreateNavigator().Evaluate
(string.Format("number({0})", new
System.Text.RegularExpressions.Regex(#"([\+\-\*])")
.Replace(expression, " ${1} ")
.Replace("/", " div ")
.Replace("%", " mod ")));
}
This is a simple Expression Evaluator using Stacks
public class MathEvaluator
{
public static void Run()
{
Eval("(1+2)");
Eval("5*4/2");
Eval("((3+5)-6)");
}
public static void Eval(string input)
{
var ans = Evaluate(input);
Console.WriteLine(input + " = " + ans);
}
public static double Evaluate(String input)
{
String expr = "(" + input + ")";
Stack<String> ops = new Stack<String>();
Stack<Double> vals = new Stack<Double>();
for (int i = 0; i < expr.Length; i++)
{
String s = expr.Substring(i, 1);
if (s.Equals("(")){}
else if (s.Equals("+")) ops.Push(s);
else if (s.Equals("-")) ops.Push(s);
else if (s.Equals("*")) ops.Push(s);
else if (s.Equals("/")) ops.Push(s);
else if (s.Equals("sqrt")) ops.Push(s);
else if (s.Equals(")"))
{
int count = ops.Count;
while (count > 0)
{
String op = ops.Pop();
double v = vals.Pop();
if (op.Equals("+")) v = vals.Pop() + v;
else if (op.Equals("-")) v = vals.Pop() - v;
else if (op.Equals("*")) v = vals.Pop()*v;
else if (op.Equals("/")) v = vals.Pop()/v;
else if (op.Equals("sqrt")) v = Math.Sqrt(v);
vals.Push(v);
count--;
}
}
else vals.Push(Double.Parse(s));
}
return vals.Pop();
}
}
static double Evaluate(string expression) {
var loDataTable = new DataTable();
var loDataColumn = new DataColumn("Eval", typeof (double), expression);
loDataTable.Columns.Add(loDataColumn);
loDataTable.Rows.Add(0);
return (double) (loDataTable.Rows[0]["Eval"]);
}
Explanation of how it works:
First, we make a table in the part var loDataTable = new DataTable();, just like in a Data Base Engine (MS SQL for example).
Then, a column, with some specific parameters (var loDataColumn = new DataColumn("Eval", typeof (double), expression);).
The "Eval" parameter is the name of the column (ColumnName attribute).
typeof (double) is the type of data to be stored in the column, which is equal to put System.Type.GetType("System.Double"); instead.
expression is the string that the Evaluate method receives, and is stored in the attribute Expression of the column. This attribute is for a really specific purpose (obvious), which is that every row that's put on the column will be fullfilled with the "Expression", and it accepts practically wathever can be put in a SQL Query. Refer to http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression(v=vs.100).aspx to know what can be put in the Expression attribute, and how it's evaluated.
Then, loDataTable.Columns.Add(loDataColumn); adds the column loDataColumn to the loDataTable table.
Then, a row is added to the table with a personalized column with a Expression attribute, done via loDataTable.Rows.Add(0);. When we add this row, the cell of the column "Eval" of the table loDataTable is fullfilled automatically with its "Expression" attribute, and, if it has operators and SQL Queries, etc, it's evaluated and then stored to the cell, so, here happens the "magic", the string with operators is evaluated and stored to a cell...
Finally, just return the value stored to the cell of the column "Eval" in row 0 (it's an index, starts counting from zero), and making a conversion to a double with return (double) (loDataTable.Rows[0]["Eval"]);.
And that's all... job done!
And here a code eaiser to understand, which does the same... It's not inside a method, and it's explained too.
DataTable MyTable = new DataTable();
DataColumn MyColumn = new DataColumn();
MyColumn.ColumnName = "MyColumn";
MyColumn.Expression = "5+5/5"
MyColumn.DataType = typeof(double);
MyTable.Columns.Add(MyColumn);
DataRow MyRow = MyTable.NewRow();
MyTable.Rows.Add(MyRow);
return (double)(MyTable.Rows[0]["MyColumn"]);
First, create the table with DataTable MyTable = new DataTable();
Then, a column with DataColumn MyColumn = new DataColumn();
Next, we put a name to the column. This so we can search into it's contents when it's stored to the table. Done via MyColumn.ColumnName = "MyColumn";
Then, the Expression, here we can put a variable of type string, in this case there's a predefined string "5+5/5", which result is 6.
The type of data to be stored to the column MyColumn.DataType = typeof(double);
Add the column to the table... MyTable.Columns.Add(MyColumn);
Make a row to be inserted to the table, which copies the table structure DataRow MyRow = MyTable.NewRow();
Add the row to the table with MyTable.Rows.Add(MyRow);
And return the value of the cell in row 0 of the column MyColumn of the table MyTable with return (double)(MyTable.Rows[0]["MyColumn"]);
Lesson done!!!
This is right to left execution, so need to use proper parathesis to execute expression
// 2+(100/5)+10 = 32
//((2.5+10)/5)+2.5 = 5
// (2.5+10)/5+2.5 = 1.6666
public static double Evaluate(String expr)
{
Stack<String> stack = new Stack<String>();
string value = "";
for (int i = 0; i < expr.Length; i++)
{
String s = expr.Substring(i, 1);
char chr = s.ToCharArray()[0];
if (!char.IsDigit(chr) && chr != '.' && value != "")
{
stack.Push(value);
value = "";
}
if (s.Equals("(")) {
string innerExp = "";
i++; //Fetch Next Character
int bracketCount=0;
for (; i < expr.Length; i++)
{
s = expr.Substring(i, 1);
if (s.Equals("("))
bracketCount++;
if (s.Equals(")"))
if (bracketCount == 0)
break;
else
bracketCount--;
innerExp += s;
}
stack.Push(Evaluate(innerExp).ToString());
}
else if (s.Equals("+")) stack.Push(s);
else if (s.Equals("-")) stack.Push(s);
else if (s.Equals("*")) stack.Push(s);
else if (s.Equals("/")) stack.Push(s);
else if (s.Equals("sqrt")) stack.Push(s);
else if (s.Equals(")"))
{
}
else if (char.IsDigit(chr) || chr == '.')
{
value += s;
if (value.Split('.').Length > 2)
throw new Exception("Invalid decimal.");
if (i == (expr.Length - 1))
stack.Push(value);
}
else
throw new Exception("Invalid character.");
}
double result = 0;
while (stack.Count >= 3)
{
double right = Convert.ToDouble(stack.Pop());
string op = stack.Pop();
double left = Convert.ToDouble(stack.Pop());
if (op == "+") result = left + right;
else if (op == "+") result = left + right;
else if (op == "-") result = left - right;
else if (op == "*") result = left * right;
else if (op == "/") result = left / right;
stack.Push(result.ToString());
}
return Convert.ToDouble(stack.Pop());
}
You could fairly easily run this through the CSharpCodeProvider with suitable fluff wrapping it (a type and a method, basically). Likewise you could go through VB etc - or JavaScript, as another answer has suggested. I don't know of anything else built into the framework at this point.
I'd expect that .NET 4.0 with its support for dynamic languages may well have better capabilities on this front.
I recently needed to do this for a project and I ended up using IronPython to do it. You can declare an instance of the engine, and then pass any valid python expression and get the result. If you're just doing simple math expressions, then it would suffice. My code ended up looking similar to:
IronPython.Hosting.PythonEngine pythonEngine = new IronPython.Hosting.PythonEngine();
string expression = "3*(2+4)";
double result = pythonEngine.EvaluateAs<double>(expression);
You'd probably not want to create the engine for each expression. You also need a reference to IronPython.dll
EDIT: Realised i should really bring the addition and subtraction out seperately aswell to make it a little bit more BODMAS compliant.
Big thanks to Rajesh Jinaga for his Stack based approach. I found it really useful for my needs. The following code is a slight modification of Rajesh's method, which processes divisions first, then multiplications, then finishes up with addition and subtraction. It will also allow the use of booleans in the expressions, where true is treated as 1 and false 0. allowing the use of boolean logic in expressions.
public static double Evaluate(string expr)
{
expr = expr.ToLower();
expr = expr.Replace(" ", "");
expr = expr.Replace("true", "1");
expr = expr.Replace("false", "0");
Stack<String> stack = new Stack<String>();
string value = "";
for (int i = 0; i < expr.Length; i++)
{
String s = expr.Substring(i, 1);
// pick up any doublelogical operators first.
if (i < expr.Length - 1)
{
String op = expr.Substring(i, 2);
if (op == "<=" || op == ">=" || op == "==")
{
stack.Push(value);
value = "";
stack.Push(op);
i++;
continue;
}
}
char chr = s.ToCharArray()[0];
if (!char.IsDigit(chr) && chr != '.' && value != "")
{
stack.Push(value);
value = "";
}
if (s.Equals("("))
{
string innerExp = "";
i++; //Fetch Next Character
int bracketCount = 0;
for (; i < expr.Length; i++)
{
s = expr.Substring(i, 1);
if (s.Equals("(")) bracketCount++;
if (s.Equals(")"))
{
if (bracketCount == 0) break;
bracketCount--;
}
innerExp += s;
}
stack.Push(Evaluate(innerExp).ToString());
}
else if (s.Equals("+") ||
s.Equals("-") ||
s.Equals("*") ||
s.Equals("/") ||
s.Equals("<") ||
s.Equals(">"))
{
stack.Push(s);
}
else if (char.IsDigit(chr) || chr == '.')
{
value += s;
if (value.Split('.').Length > 2)
throw new Exception("Invalid decimal.");
if (i == (expr.Length - 1))
stack.Push(value);
}
else
{
throw new Exception("Invalid character.");
}
}
double result = 0;
List<String> list = stack.ToList<String>();
for (int i = list.Count - 2; i >= 0; i--)
{
if (list[i] == "/")
{
list[i] = (Convert.ToDouble(list[i - 1]) / Convert.ToDouble(list[i + 1])).ToString();
list.RemoveAt(i + 1);
list.RemoveAt(i - 1);
i -= 2;
}
}
for (int i = list.Count - 2; i >= 0; i--)
{
if (list[i] == "*")
{
list[i] = (Convert.ToDouble(list[i - 1]) * Convert.ToDouble(list[i + 1])).ToString();
list.RemoveAt(i + 1);
list.RemoveAt(i - 1);
i -= 2;
}
}
for (int i = list.Count - 2; i >= 0; i--)
{
if (list[i] == "+")
{
list[i] = (Convert.ToDouble(list[i - 1]) + Convert.ToDouble(list[i + 1])).ToString();
list.RemoveAt(i + 1);
list.RemoveAt(i - 1);
i -= 2;
}
}
for (int i = list.Count - 2; i >= 0; i--)
{
if (list[i] == "-")
{
list[i] = (Convert.ToDouble(list[i - 1]) - Convert.ToDouble(list[i + 1])).ToString();
list.RemoveAt(i + 1);
list.RemoveAt(i - 1);
i -= 2;
}
}
stack.Clear();
for (int i = 0; i < list.Count; i++)
{
stack.Push(list[i]);
}
while (stack.Count >= 3)
{
double right = Convert.ToDouble(stack.Pop());
string op = stack.Pop();
double left = Convert.ToDouble(stack.Pop());
if (op == "<") result = (left < right) ? 1 : 0;
else if (op == ">") result = (left > right) ? 1 : 0;
else if (op == "<=") result = (left <= right) ? 1 : 0;
else if (op == ">=") result = (left >= right) ? 1 : 0;
else if (op == "==") result = (left == right) ? 1 : 0;
stack.Push(result.ToString());
}
return Convert.ToDouble(stack.Pop());
}
I know there is likely to be a cleaner way of doing it, thought id just share the first look at it in case anyone finds it usefull.
Many thanks to Ramesh. I used a version of his simple code to pull a string out a database and use it to do boolean operations in my code.
x is a number like 1500 or 2100 or whatever.
function would be a stored evaluation like x > 1400 and x < 1600
function = relation[0].Replace("and","&&").Replace("x",x);
DataTable f_dt = new DataTable();
var f_var = f_dt.Compute(function,"");
if (bool.Parse(f_var.ToString()) { do stuff }
There is not. You will need to use some external library, or write your own parser. If you have the time to do so, I suggest to write your own parser as it is a quite interesting project. Otherwise you will need to use something like bcParser.
Short answer: I don't think so. C# .Net is compiled (to bytecode) and can't evaluate strings at runtime, as far as I know. JScript .Net can, however; but I would still advise you to code a parser and stack-based evaluator yourself.