方案1.动态编译,2,script脚本,3.linq.expression
1.软件开放脚本录入容器(字符串),
2.动态编译成方法,
3.根据需要进行调用(可定义输入参数和返回类型) ,后期依据接口,开放式编程
class DyncCompiler
{
/// <summary>
/// 动态编译:解释器,返回方法体
/// </summary>
/// <param name="RTYPE">返回参数类型</param>
/// <param name="para">参数:《参数名,参数类型》</param>
/// <param name="methodstr">自定义方法体</param>
/// <returns>方法信息,或委托</returns>
public static MethodInfo Compiler(string RTYPE, Dictionary<string, string> para, string methodstr)
{
//CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
CodeDomProvider cdp = CodeDomProvider.CreateProvider("C#");
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add("System.Linq.dll");
cp.ReferencedAssemblies.Add("System.Data.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.GenerateExecutable = false; //false:生成dll ,true:生成exe
cp.GenerateInMemory = true;
//cp.OutputAssembly = "SimpleCompile.exe";
string hello = "using System; " +
"using System.Windows.Forms; " +
"using System.Linq; " +
"using System.Data;" +
"using System.Collections.Generic;" +
"namespace HelloWorld " +
"{ " +
" public class HelloWorld" +
" {" +
"public static " + (string.IsNullOrEmpty(RTYPE) ? "void" : RTYPE) + " SayHello (" + getpara(para) + " )" +
"{" +
methodstr +
"}" +
" }" +
"}";
// 编译结果
CompilerResults cr = cdp.CompileAssemblyFromSource(cp, hello);
if (cr.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError d in cr.Errors)
sb.AppendLine($"{d.Line},{d.ErrorNumber},{d.ErrorText}");
throw new Exception(sb.ToString());
}
else
{
// 编译后的程序集
Assembly ass = cr.CompiledAssembly;
//创建类实例
//ass.CreateInstance ("HelloWorld.HelloWorld")
//获取类方法(固定名)
Type type = ass.GetType("HelloWorld.HelloWorld");
MethodInfo mi = type.GetMethod("SayHello");
// mi.Invoke(null, new object[] { }); //方法体执行
//Delegate del = mi.CreateDelegate(typeof(Action<string>));
//del.DynamicInvoke();//委托执行
return mi;
}
}
/// <summary>
/// 参数列表
/// </summary>
/// <param name="para"></param>
/// <returns></returns>
static string getpara(Dictionary<string, string> para)
{
if (para == null)
return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (var d in para)
{
sb.Append($" {d.Value} {d.Key},");
}
return sb.ToString().TrimEnd(',');
}
/// <summary>
/// 内部执行:表达式
/// eg1:Evaluate<int>("(1+2)*3");
/// eg2:Evaluate<int>("P1+P2*P3",4,5,6);
/// eg3:DyncCompiler.Evaluate<int>(P1+P2*P3,x,y,z); int x=4,y=5,z=6
/// </summary>
/// <typeparam name="T">返回的数据类型</typeparam>
/// <param name="code">表达式代码</param>
/// <param name="parameters">可选参数列表(按顺序P1,P2)</param>
/// <returns></returns>
public static T Evaluate<T>(string code, params object[] parameters)
{
if (!code.Contains("return"))
code = "return " + code;
if (!code.EndsWith(";"))
code += ";";
Dictionary<string, string> para = null;
if (parameters.Count() > 0)
{
para = new Dictionary<string, string>();
int i = 1;
foreach (var p in parameters)
{
para[$"P{i}"] = p.GetType().Name;
i++;
}
}
var d = DyncCompiler.Compiler(typeof(T).Name, para, code);
return (T)d.Invoke(null, parameters ); //执行并返回整型数据
}
winform 执行:
//内部执行
private void button6_Click(object sender, EventArgs e)
{
int x = 4, y = 5, z = 6;
var n = DyncCompiler.Evaluate<int>(“P1+P2*p3”,x,y,z);
MessageBox.Show(n.ToString());
}
MethodInfo vd;
private void button1_Click(object sender, EventArgs e)
{
try
{
vd = DyncCompiler.Compiler(CmbReturnType.Text, para, richTextBox1.Text); //返回类型,参数字典,脚本内容
button2.Enabled = vd != null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "语法错误");
vd = null;
button2.Enabled = false;
}
}
//执行
private void button2_Click(object sender, EventArgs e)
{
var n = vd.Invoke(null, new object[] { TxtInput1.Text, Txtinput2.Text });// vd.DynamicInvoke(TxtInput1.Text);
if (n != null)
MessageBox.Show(n.ToString());
}
扩展方案2: 使用MSScriptControl
到软的网站上下载Windows Script Control,它是一个ActiveX® 控件,所以在.NET中使用我Interop了一下。下载安装完成后,新建一个C#的Windows应用程序项目,在解决方案资源管理器中选中引用节点,右键点击选择添加引用菜单,弹出添加引用对话框,单击浏览找到安装Windows Script Control的目录,选取msscript.ocx文件确定。那么在引用节点下会增加一个MSScriptControl组件
//执行:事例
private void button7_Click(object sender, EventArgs e)
{
var d = Js.init.Eval(textBox1.Text);
if (d != null)
MessageBox.Show(d.ToString());
}
//脚本语言
public enum ScriptLanguage
{
JScript,
VBscript,
JavaScript
}
//脚本类
public class Js
{
public static Js init = new Js();
private Js()
{
msc = new MSScriptControl.ScriptControl();
msc.AllowUI = true;
msc.UseSafeSubset = true;
Language = ScriptLanguage.JavaScript;
((DScriptControlSource_Event)this.msc).Error += new DScriptControlSource_ErrorEventHandler(ScriptEngine_Error);
}
MSScriptControl.ScriptControl msc;
ScriptLanguage _Language;
public ScriptLanguage Language
{
set
{
if (value == _Language)
return;
msc.Language = value.ToString();
_Language = value;
}
}
public event Action<string> RunError;
void ScriptEngine_Error()
{
err("脚本执行错误!");
}
void err(string errmsg)
{
if (RunError != null)
RunError(errmsg);
}
/// <summary>
/// 运行Eval方法
/// </summary>
/// <param name="expression">表达式</param>
/// <returns>返回值object</returns>
public object Eval(string expression)
{
try
{
return msc.Eval(expression);//计算表达式并返回结果。
}
catch (Exception ex)
{
err(ex.Message);
}
return null;
}
/// <summary>
/// 运行Run方法
/// </summary>
/// <param name="mainFunctionName">入口函数名称</param>
/// <param name="parameters">参数</param>
/// <param name="codeBody">函数体</param>
/// <returns>返回值object</returns>
public object Run(string mainFunctionName, object[] parameters, string codeBody)
{
try
{
this.msc.AddCode(codeBody);//向模块添加指定代码。可多次调用 AddCode 方法。
return msc.Run(mainFunctionName, ref parameters);//运行指定过程。
}
catch (Exception ex)
{
err(ex.Message);
}
return null;
}
public void Reset()
{
msc.Reset();//:放弃所有已经添加到 ScriptControl 中的 Script 代码和对象。
}
}
扩展方案3: System.Linq.Expressions
Expression表达式树(C#)
1.Expression d= 将字符串表达式转换成Expression();
2.LambdaExpression lambda=Expression.Lambda(d); // 转为lambda 表达式
3.Delegate del= lambda.Compile(); //转为委托类型
4.del.DynamicInvoke();//委托执行