public partial class Form1 : Form
{
public Form1()
{
InitializeComponent(); }
public int a=1;
public static int b=2;
private int c=3;
private static int d=4;
void button1_Click(object sender, EventArgs e)
{
object expression=d-a*b;
MessageBox.Show(expression.ToString());
//如果expression是通过一个字符串获得的
//比如是通过textBox1.Text获得
//假设当前a=1,b=2,c=3,d=4
//如果textBox1.Text="d+c",则结果为7
//如果textBox1.Text="a-b*c*d",则结果为-23
//如何计算其值呢?
//前提是不能解析表达式,也就是不能像计算器一样
//先解析出运算数和运算符,然后反射获得运算数的值,再求值
//希望通过动态编译来求值,比如CodeDom之类的
}
//Tick事件本身并不重要,只是想表明各个字段的值是时刻变化的
//希望取到当前的值
void timer1_Tick(object sender, EventArgs e)
{
Random r=new Random();
a=32;
b=r.Next(100);
c=a*b;
d=a+c*2;
}
}
现在只知道结果值和4个元素,4个元素的值和之间的运算符都在变
这能求出各元素的值吗看了看CodeDom,好象是用来生成cs\dll\exe文件的,和这问题有什么关系
// 表达式使用 C# 语法,可带一个的自变量(x)。
// 表达式的自变量和值均为(double)类型。
// 使用举例:
// Expression expression = new Expression("Math.Sin(x)");
// Console.WriteLine(expression.Compute(Math.PI / 2));
// expression = new Expression("double u = Math.PI - x;" +
// "double pi2 = Math.PI * Math.PI;" +
// "return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;");
// Console.WriteLine(expression.Compute(0));
using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
using System.Text;
namespace Skyiv.Util
{
sealed class Expression
{
object instance;
MethodInfo method;
public Expression(string expression)
{
if (expression.IndexOf("return") < 0) expression = "return " + expression + ";";
string className = "Expression";
string methodName = "Compute";
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = true;
CompilerResults cr = new CSharpCodeProvider().CompileAssemblyFromSource(p, string.
Format("using System;sealed class {0}{{public double {1}(double x){{{2}}}}}",
className, methodName, expression));
if(cr.Errors.Count > 0)
{
string msg = "Expression(\"" + expression + "\"): \n";
foreach (CompilerError err in cr.Errors) msg += err.ToString() + "\n";
throw new Exception(msg);
}
instance = cr.CompiledAssembly.CreateInstance(className);
method = instance.GetType().GetMethod(methodName);
}
public double Compute(double x)
{
return (double)method.Invoke(instance, new object [] { x });
}
}
}
把变量写到数据库中
然后把表达式嵌入到SQL语句中,借用SQL语句的解析功能
比如string expression = "a-b*c";
string sql = "select " + expression + " as result From tb_cal";
1、就是4楼的兄弟的方法,这个我们在项目中有使用过类似的方法;再次自己封装一下就ok;
2、解析 expreesion ,其实这个不是什么特别难得事情,用正则,或则直接进行字符串解析就可以知道。记得以前自己就进行过类似的解析,稍后找找代码看看;
3、记得在看二叉树的时候好像提到过解决这样的事情,可以看看二叉树的算法。不错。
public static int a=1;
public static int b=2;
private static int c=3;
private static int d=4;
然后把表达式嵌入到SQL语句中,借用SQL语句的解析功能
比如 string expression = "a-b*c";
string sql = "select " + expression + " as result From tb_cal";
动态生成数学表达式并计算其值
// **********.cs - 动态生成数学表达式并计算其值
// 表达式使用 C# 语法,可带一个的自变量(x)。
// 表达式的自变量和值均为(double)类型。
// 使用举例:
// ********** ********** = new **********("sqrt(sin(x) * sin(x) + cos(x) ^ PI)");
// Console.WriteLine(**********.Compute(PI / 2));
// ********** = new **********("double u = Math.PI - x;" +
// "double pi2 = Math.PI * Math.PI;" +
// "return 3 * x * x + Math.Log(u * u) / pi2 / pi2 + 1;");
// Console.WriteLine(**********.Compute(0));
using System;
using System.CodeDom.Compiler;
using Microsoft.VisualBasic; using System.Globalization;
using System.Reflection;
using System.Text;
namespace Skyiv.Util
{
sealed class **********
{
object instance;
MethodInfo method;
public **********(string **********)
{
if (**********.ToUpper(CultureInfo.InvariantCulture).IndexOf("RETURN") < 0) ********** = "Return " + **********;
string className = "**********";
string methodName = "Compute";
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = true;
CompilerResults cr = new VBCodeProvider().CompileAssemblyFromSource(p, string.
Format(@"Option Explicit Off
Option Strict Off
Imports System, System.Math, Microsoft.VisualBasic
NotInheritable Class {0}
Public Function {1}(x As Double) As Double
{2}
End Function
End Class",
className, methodName, **********)); if(cr.Errors.Count > 0)
{
string msg = "**********(\"" + ********** + "\"): \n";
foreach (CompilerError err in cr.Errors) msg += err.ToString() + "\n";
throw new Exception(msg);
}
instance = cr.CompiledAssembly.CreateInstance(className);
method = instance.GetType().GetMethod(methodName);
}
public double Compute(double x)
{
return (double)method.Invoke(instance, new object [] { x });
}
}
}
DataTable table = new DataTable();
table.Columns.Add("d", typeof(double));
table.Columns.Add("a", typeof(double));
table.Columns.Add("b", typeof(double));
table.Columns.Add("result", typeof(double), "d-a*b"); DataRow row = table.NewRow();
row["d"] = 20;
row["a"] = 4;
row["b"] = 4;
table.Rows.Add(row);
然后求row["result"].ToString()即可
------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.JScript;
using Microsoft.Vsa;//要添加两个引用Microsoft.JScript;Microsoft.Vsa;namespace JSEval
{
class Program
{
public static int a = 1;
public static int b = 2;
private static int c = 3;
private static int d = 4; static void Main(string[] args)
{
string expression = "var a=1,b=2,c=3,d=4;"; //要把变量的定义加进去
expression += "d - a * b"; //表达式
//System.Console.WriteLine(expression.ToString()); Microsoft.JScript.Vsa.VsaEngine ve = Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
Console.WriteLine(Microsoft.JScript.Eval.JScriptEvaluate(expression, ve)); //结果2
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Globalization;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;namespace App
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} string GenerateCode()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("using System.Windows.Forms;");
sb.AppendLine("namespace Calc_Namespace");
sb.AppendLine("{");
sb.AppendLine(" public class Calc_Class");
sb.AppendLine(" {");
sb.AppendLine(" public void Calc_Fun(TextBox tb2)");
sb.AppendLine(" {");
sb.AppendLine(" try");
sb.AppendLine(" {");
sb.AppendLine(" int a = 1;");
sb.AppendLine(" int b = 2;");
sb.AppendLine(" int c = 3;");
sb.AppendLine(" int d = 4;");
sb.AppendLine(" int result = " + this.textBox1.Text + ";");
sb.AppendLine(" tb2.Text = result.ToString();");
sb.AppendLine(" }");
sb.AppendLine(" catch (Exception ex)");
sb.AppendLine(" {");
sb.AppendLine(" ex.ToString();");
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine("}");
string code = sb.ToString();
Console.WriteLine(code);
Console.WriteLine();
return code;
} private void DynamicCodeGenerate()
{
// 1.CSharpCodePrivoder
CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider(); // 2.ICodeComplier
ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler(); // 3.CompilerParameters
CompilerParameters objCompilerParameters = new CompilerParameters();
objCompilerParameters.ReferencedAssemblies.Add("System.dll");
objCompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true; // 4.CompilerResults
CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode()); if (cr.Errors.HasErrors)
{
Console.WriteLine("Compiler Error: ");
foreach (CompilerError err in cr.Errors)
{
Console.WriteLine(err.ErrorText);
}
}
else
{
// 通过反射,调用Calc的实例
Assembly objAssembly = cr.CompiledAssembly;
object objMain = objAssembly.CreateInstance("Calc_Namespace.Calc_Class");
MethodInfo objMI = objMain.GetType().GetMethod("Calc_Fun");
objMI.Invoke(objMain, new Object[] { this.textBox2 });
}
} private void button1_Click(object sender, EventArgs e)
{
System.Threading.Thread td = new System.Threading.Thread(new System.Threading.ThreadStart(this.DynamicCodeGenerate));
td.Start();
}
}
}
所以这样的表达都是错误的:
string expression = "var a=1,b=2,c=3,d=4;"; //要把变量的定义加进去
sb.AppendLine(" int a = 1;");
sb.AppendLine(" int b = 2;");
sb.AppendLine(" int c = 3;");
sb.AppendLine(" int d = 4;");我只是举例说是1,2,3,4,实际上我在Tick事件中是用随机数生成的,编译时根本不确定
sb.AppendLine(" int b = 2;");
sb.AppendLine(" int c = 3;");
sb.AppendLine(" int d = 4;"); 这个不需要写死的啊
string expression = textBox2.Text.Replace("a", a.ToString()).Replace("b", b.ToString()).Replace("c", c.ToString()).Replace("d", d.ToString());
MessageBox.Show(new DataTable().Compute(expression, "").ToString());
string expression = "var a=1,b=2,c=3,d=4;"; //要把变量的定义加进去
expression += "d - a * b"; //表达式这里只是举例,你不需要将它写死.
比如用变量:
string expression = "var a="+a.ToString()+ ",b="+b.ToString()+",d="+ToString()+";";
textBox1.Text="a+button1.Text.Length+somefield*new Random().Next";1.其中a和somefield是字段,我类里面可能有很多很多字段,我并不知道textBox1.Text会访问哪些字段,所以不可能:
string expression = "var a="+a.ToString()+ ",b="+b.ToString()+",d="+ToString()+";";
总不可能把所有字段都这样写下来吧?2.button1.Text.Length,这个根本就不是字段,是要取得button1的文本长度,而且事先不知道会这样取,如果
textBox1.Text="Form.ActiveForm.Controls.Count",取得的就是另一个值了,在textBox1里输入什么,事先不能预知我想了一下,这个问题就类似于(当然,这只是我的感觉,如果不需要修改,就可以实现,那更好):
能否动态的修改一个类,比如修改类中某个方法的实现;又比如给类添加某个成员
//using System;
class Class1
{
public static void Main()
{
System.Console.WriteLine("Hello World!");
//中缀 => 后缀表达式
string s = "( 1.9 + (20 + 41) / (25 * 11) - 3 ) * 2"; //中缀; //中缀
string S = ""; //后缀
char[] Operators = new char[s.Length];
int Top = -1;
for (int i = 0; i < s.Length; i++)
{
char C = s[i];
switch (C)
{
case ' ' : //忽略空格
break;
case '+' : //操作符
case '-' :
while (Top >= 0) //栈不为空时
{
char c = Operators[Top--]; //pop Operator
if (c == '(')
{
Operators[++Top] = c; //push Operator
break;
}
else
{
S = S + c;
}
}
Operators[++Top] = C; //push Operator
S += " ";
break;
case '*' : //忽略空格
case '/' :
while (Top >= 0) //栈不为空时
{
char c = Operators[Top--]; //pop Operator
if (c == '(')
{
Operators[++Top] = c; //push Operator
break;
}
else
{
if (c == '+' || c == '-')
{
Operators[++Top] = c; //push Operator
break;
}
else
{
S = S + c;
}
}
}
Operators[++Top] = C; //push Operator
S += " ";
break;
case '(' :
Operators[++Top] = C;
S += " ";
break;
case ')' :
while (Top >= 0) //栈不为空时
{
char c = Operators[Top--]; //pop Operator
if (c == '(')
{
break;
}
else
{
S = S + c;
}
}
S += " ";
break;
default :
S = S + C;
break;
}
}
while (Top >= 0)
{
S = S + Operators[Top--]; //pop Operator
} System.Console.WriteLine(S); //后缀 //后缀表达式计算
double[] Operands = new double[S.Length];
double x, y, v;
Top = - 1;
string Operand = "";
for (int i = 0; i < S.Length; i++)
{
char c = S[i];
if ((c >= '0' && c <= '9') || c == '.')
{
Operand += c;
} if ((c == ' ' && Operand != "") || i == S.Length - 1)
{
Operands[++Top] = System.Convert.ToDouble(Operand) ; //push Operands
Operand = "";
} if (c == '+' || c == '-' || c == '*' || c == '/')
{
if ((Operand != ""))
{
Operands[++Top] = System.Convert.ToDouble(Operand) ; //push Operands
Operand = "";
}
y = Operands[Top--]; //pop 双目运算符的第二操作数 (后进先出)注意操作数顺序对除法的影响
x = Operands[Top--]; //pop 双目运算符的第一操作数
switch (c)
{
case '+' :
v = x + y;
break;
case '-' :
v = x - y;
break;
case '*' :
v = x * y;
break;
case '/' :
v = x / y; // 第一操作数 / 第二操作数 注意操作数顺序对除法的影响
break;
default :
v = 0;
break;
}
Operands[++Top] = v; //push 中间结果再次入栈
}
}
v = Operands[Top--]; //pop 最终结果
System.Console.WriteLine(v);
System.Console.ReadLine();
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text.RegularExpressions;namespace WinCodeDomTest
{
public partial class FrmMain : Form
{
public int a = 1;
public static int b = 2;
private int c = 3;
private static int d = 4; public FrmMain()
{
InitializeComponent();
} private void FrmMain_Load(object sender, EventArgs e)
{
Timer1.Enabled = true;
txtInput.Text = "a-b*c*d";
} private void btnOK_Click(object sender, EventArgs e)
{
Execute();
}
/// <summary>
/// 执行
/// </summary>
private void Execute()
{
string namespaceName = "CalculatorInMemory";
string className = "Calculator";
string methodName = "Calculate";
string expression=txtInput.Text;
//程序源码
string sourceCode = CreateSourceCode(namespaceName, className, methodName, expression);
//编译
CSharpCodeProvider cSharpCodeProvider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
CompilerResults compilerResults = cSharpCodeProvider.CompileAssemblyFromSource(compilerParameters, sourceCode);
StringBuilder sbError = new StringBuilder();
if (compilerResults.Errors.HasErrors)
{
sbError.Append("编译错误: ");
foreach (CompilerError err in compilerResults.Errors)
{
sbError.Append(err.ErrorText);
sbError.Append("\r\n");
}
txtContent.Text = sbError.ToString();
return;
}
//执行
Assembly assembly = compilerResults.CompiledAssembly;
Type type = assembly.GetType(string.Format("{0}.{1}", namespaceName, className));
MethodInfo methodInfo = type.GetMethod(methodName);
int[] intArray = new int[] { a, b, c, d };
object objResult = methodInfo.Invoke(null, new object[]{intArray});
//显示
string templete = @"
a = {0};
b = {1};
c = {2};
d = {3};{4} = {5};
";
txtContent.Text = string.Format(templete,a,b,c,d,expression,objResult);
} /// <summary>
/// 产生源代码
/// </summary>
/// <param name="expression"></param>
/// <param name="intArray"></param>
/// <returns></returns>
private string CreateSourceCode(string namespaceName, string className, string methodName, string expression)
{
string templete = @"
using System;
namespace {0}
{
public class {1}
{
public static string {2}(params int[] intArray)
{
int a = intArray[0];
int b = intArray[1];
int c = intArray[2];
int d = intArray[3];
int result = 0;
try
{
result = {3};
return result.ToString();
}
catch(Exception ex)
{
return string.Format(""错误: {{0}}"",ex.Message);
}
}
}
}";
string sourceCode = templete.FormatEx(namespaceName,className,methodName,expression);
return sourceCode;
} private void Timer1_Tick(object sender, EventArgs e)
{
Random random = new Random();
a = 32;
b = random.Next(100);
c = a * b;
d = a + c * 2;
}
} public static class StringMethodExpand
{
private class ForReplace
{
private object[] args;
public ForReplace(object[] args)
{
this.args = args;
} public string Replace(Match match)
{
if (!string.IsNullOrEmpty(match.Groups[1].Value))
{
return "{";
}
if (!string.IsNullOrEmpty(match.Groups[2].Value))
{
return "}";
}
int index = int.Parse(match.Groups[4].Value);
return args[index].ToString();
}
}
private static Regex regFormat = new Regex("(\\{\\{)|(\\}\\})|(\\{(\\d+)\\})", RegexOptions.Compiled);
/// <summary>
/// 与string.Format具有相同功能, 区别在于: "ab{cd{0}ef}gh" 无需写成 "ab{{cd{0}ef}}gh"
/// 作者: 医手
/// </summary>
/// <param name="templete"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string FormatEx(this string templete, params object[] args)
{
ForReplace forReplace = new ForReplace(args);
string result = regFormat.Replace(templete, new MatchEvaluator(forReplace.Replace));
return result;
}
}
}
代码如下,仅供参考:
private object DynamicCalculate(string expression)
{
string propertyName = "DynamicProperty";
string className = "DynamicClass"; // 声明一个新的类型继承当前的类
CodeTypeDeclaration classType = new CodeTypeDeclaration(className);
classType.TypeAttributes = TypeAttributes.Public;
classType.BaseTypes.Add(new CodeTypeReference(this.GetType())); // 增加一个属性计算所需要的表达式的值
CodeMemberProperty property = new CodeMemberProperty();
classType.Members.Add(property);
property.Name = propertyName;
property.Type = new CodeTypeReference(typeof(object));
property.Attributes = MemberAttributes.Public; // 通过expression参数动态设置GET代码,必须保证子类能够访问表达式中的对象
CodeMethodReturnStatement codeget = new CodeMethodReturnStatement();
codeget.Expression = new CodeSnippetExpression(expression);
property.GetStatements.Add(codeget);
Assembly asmCurrent = this.GetType().Assembly; // 设置编译参数
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true; //添加所需要的DLL
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add(Path.GetFileName(asmCurrent.Location));
//创建编译单元
CodeCompileUnit codeUnit = new CodeCompileUnit();
codeUnit.Namespaces.Add(new CodeNamespace(this.GetType().Namespace));
codeUnit.Namespaces[0].Types.Add(classType); //添加所需要的命名空间
codeUnit.Namespaces[0].Imports.Add(new CodeNamespaceImport("System"));
codeUnit.Namespaces[0].Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
codeUnit.Namespaces[0].Imports.Add(new CodeNamespaceImport(this.GetType().Namespace));
//编译该类
CompilerResults cr = new CSharpCodeProvider().CompileAssemblyFromDom(cp, codeUnit);
if (cr.Errors.Count > 0)
{
string msgError = "";
foreach (CompilerError err in cr.Errors)
{
msgError += err.ToString() + "\n";
} throw new Exception(msgError);
} // 创建实例
object instance = cr.CompiledAssembly.CreateInstance(codeUnit.Namespaces[0].Name + "." + className); // 获取动态创建的属性
PropertyInfo proInfo = instance.GetType().GetProperty(propertyName); object result = null;
if (proInfo != null)
{
result = proInfo.GetValue(instance, null);
} return result;
}
//先解析出运算数和运算符,然后反射获得运算数的值,再求值
//希望通过动态编译来求值,比如CodeDom之类的没见过这样的需求。
不能解析表达式是为了什么?CodeDom就不解析了?