1.利用正則表達式進行語義分析,這種方式需要考慮的東西太多。
2.利用C#對“動態語言”的支持。也就是說,將654*6+65-27/654整個字符串當做壹個string類型參數傳入某壹方法 然後返回執行後的結果,相信這個應該很適合妳,下面是壹個類,妳直接用以下方法調用即可:
如:
public class ProgramTest
{
static void Main(string[] args)
{
string res = string.Empty;
string error = string.Empty;
res = Evaluator.ReturnRsult("654*6+65-27/654", out error); //這裏就是妳要傳進去的式子,只要是標準的式子便可。
if (!string.IsNullOrEmpty(error))
{
Console.WriteLine(error);
}
else
{
Console.WriteLine("執行結果為:" + res);
}
Console.Read();
}
}
------
下面就是實現功能的類,copy到您的程序中就行,註意引用到的名字空間有:
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Text.RegularExpressions;
------------------------
/// <summary>
/// C#代碼執行器,提供動態執行C#代碼
/// </summary>
public class Evaluator
{
private static CSharpCodeProvider cCodeProder = null;
private static CompilerParameters compPars = null;
private static CompilerResults compResult = null;
private static Regex rexLastCode = new Regex(@"(print:).+;\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase); //用於搜索最後壹條代碼的位置
static Evaluator()
{
cCodeProder = new CSharpCodeProvider();
}
/// <summary>
/// 執行指定的代碼
/// </summary>
/// <param name="strCodes"></param>
/// <returns></returns>
private static string Eval(string strCodes, out string strErrText)
{
#region 編譯代碼
strErrText = InitCompile(ref strCodes);
if (strErrText != null) return null;
try
{
compResult = cCodeProder.CompileAssemblyFromSource(compPars, new string[] { strCodes });
}
catch (NotImplementedException nie)
{
strErrText = nie.Message;
return null;
}
if (compResult.Errors.HasErrors)
{
StringBuilder sbErrs = new StringBuilder(strCodes + System.Environment.NewLine);
sbErrs.Append("您所提供的C#代碼中存在語法錯誤!" + System.Environment.NewLine);
foreach (CompilerError err in compResult.Errors)
{
sbErrs.AppendFormat("{0},{1}" + System.Environment.NewLine, err.ErrorNumber, err.ErrorText);
}
strErrText = sbErrs.ToString();
return null;
}
#endregion
Assembly assembly = compResult.CompiledAssembly;
object prgInsl = assembly.CreateInstance("System._ClassEvaluatorCompiler");
MethodInfo medInfo = prgInsl.GetType().GetMethod("PrintResult");
string strRetn;
try
{
strRetn = medInfo.Invoke(prgInsl, null).ToString();
return strRetn;
}
catch (Exception exMsg)
{
strErrText = exMsg.Message;
return null;
}
}
/// <summary>
/// 預編譯代碼
/// </summary>
/// <param name="strCodes">待編譯的源代碼</param>
/// <returns>如果錯誤則返回錯誤消息</returns>
private static string InitCompile(ref string strCodes)
{
List<string> lstRefs = new List<string>();//代碼字符串中的include引用程序集------未使用
List<string> lstUsings = new List<string>();//代碼字符串中的using引用命名空間
#region 分離引用的程序集與命名空間
int point = 0;
string strTemp;
char[] cCodes = strCodes.ToCharArray();
for (int i = 0; i < cCodes.Length; ++i)
{
if (cCodes[i] == '\n' || (cCodes[i] == '\r' && cCodes[i + 1] == '\n'))
{
strTemp = strCodes.Substring(point, i - point);
if (strTemp.TrimStart(new char[] { ' ' }).StartsWith("using "))
{
strTemp = strTemp.Substring(6).Trim();
if (!lstUsings.Contains(strTemp))
{
lstUsings.Add(strTemp);
}
else
{
return "預編譯失敗,代碼中不允許包含重復命名空間導入。" + System.Environment.NewLine + "using " + strTemp;
}
point = cCodes[i] == '\n' ? i + 1 : i + 2;
++i;
}
else if (strTemp.TrimStart(new char[] { ' ' }).StartsWith("include "))
{
strTemp = strTemp.Substring(8).Trim().ToLower();
if (!lstRefs.Contains(strTemp))
{
lstUsings.Add(strTemp);
}
else
{
return "預編譯失敗,代碼中不允許包含重復的程序集引用。" + System.Environment.NewLine + "include " + strTemp;
}
point = cCodes[i] == '\n' ? i + 1 : i + 2;
++i;
}
else
{
break;
}
}
}
strCodes = strCodes.Substring(point);
#endregion
#region 初始化編譯參數
if (compPars == null)
{
compPars = new CompilerParameters();
compPars.GenerateExecutable = false;
compPars.GenerateInMemory = true;
}
//string workDir = System.Web.HttpContext.Current.Server.MapPath("~") + "Bin\\";
//string workDir = System.Environment.CurrentDirectory;
compPars.ReferencedAssemblies.Clear();
compPars.ReferencedAssemblies.Add("system.dll");
compPars.ReferencedAssemblies.Add("system.data.dll");
compPars.ReferencedAssemblies.Add("system.xml.dll");
//compPars.ReferencedAssemblies.Add(workDir + "BLL.dll");
//compPars.ReferencedAssemblies.Add(workDir + "Component.dll");
//compPars.ReferencedAssemblies.Add(workDir + "Model.dll");
//compPars.ReferencedAssemblies.Add(workDir + "Utility.dll");
foreach (string str in lstRefs)
{
compPars.ReferencedAssemblies.Add(str);
}
#endregion
StringBuilder sbRetn = new StringBuilder();
#region 生成代碼模板
///*為代碼添加return 語句*/
Match match = rexLastCode.Match(strCodes);
if (match.Success)
{
strCodes = string.Format("{0}\r\nreturn {1}", strCodes.Substring(0, match.Groups[1].Index), strCodes.Substring(match.Groups[1].Index + match.Groups[1].Length));
}
else
{
strCodes = strCodes.Trim();//把要運行的代碼字符串作為返回值---作為輸出 - 顯示運行的字符串源碼
}
/*拼接代碼*/
foreach (string str in lstUsings)
{
sbRetn.AppendLine("using " + str);
}
sbRetn.AppendLine("namespace System{");
sbRetn.AppendLine("public class _ClassEvaluatorCompiler{");
sbRetn.AppendLine("public static object PrintResult(){");
sbRetn.AppendLine(strCodes);
sbRetn.AppendLine("}}}");
#endregion
strCodes = sbRetn.ToString();
return null;
}
/// <summary>
/// 執行壹段表達式
/// </summary>
/// <param name="info">要執行的表達式字符串</param>
/// <param name="error">錯誤提示語句</param>
/// <returns>返回執行結果</returns>
public static string ReturnRsult(string info, out string error)
{
string returnStr = string.Empty;
info = "return " + info + ";";
returnStr = Eval(info, out error);
return returnStr;
}
}