using Microsoft.CSharp;
|
using System;
|
using System.CodeDom.Compiler;
|
using System.Collections.Generic;
|
using System.Reflection;
|
using System.Text;
|
using Newtonsoft.Json;
|
//using EPAModelNameSpace;
|
//using System.Security.AccessControl;
|
using System.IO;
|
using System.Linq;
|
using System.Data;
|
using Hydro.CommonBase;
|
using System.Text.RegularExpressions;
|
//using System.Security.Cryptography.X509Certificates;
|
//using Hydro.ConfigModel;
|
|
namespace Hydro.CodeProvider
|
{
|
public class EvalResult
|
{
|
|
public EvalResult(object obj, List<MethodInfo> infos)
|
{
|
|
this.obj = obj;
|
this.infos = infos;
|
}
|
public object obj;
|
public List<MethodInfo> infos;
|
|
}
|
/// <summary>
|
/// 使用方法:
|
/// 示例化MyEval,传入代码片段,选择模板类型或传入自定义模板
|
/// </summary>
|
[Serializable]
|
public class Eval
|
{
|
int paramNum;
|
string tempCode=null;
|
List<string> refs = new List<string>();
|
List<string> usings = new List<string>();
|
string code;
|
object tmp;
|
public void SetTmp(object tmp)
|
{
|
this.tmp = tmp;
|
}
|
|
public void SetMethodInfo(List<MethodInfo> info)
|
{
|
this.mi=info[FunctionIndex];
|
}
|
int FunctionIndex = -1;
|
MethodInfo mi;
|
public bool isInit;
|
public string errString;
|
|
//static MyEval instance;
|
//static List<MethodInfo> mis=new List<MethodInfo>();
|
public static dynamic CompileTotalInstance(EvalTemplate me_temp)
|
{
|
|
var code= me_temp.Get_code();
|
var me = new Eval(code);
|
//me.tmp = me.getInstance();
|
if (!me.isInit)
|
{
|
return me.errString;
|
}
|
else
|
{
|
List<MethodInfo> mis = new List<MethodInfo>();
|
Type type = me.tmp.GetType();
|
for(int i=0;i< me_temp.Count;i++)
|
{
|
mis.Add(type.GetMethod($"TMethod{i}"));
|
}
|
return new EvalResult(me.tmp,mis);
|
|
}
|
}
|
/// <summary>
|
/// 构造函数
|
/// </summary>
|
/// <param name="CharpCode">自由编写;参数:List<double> paramArray,返回值:double;</param>
|
/// <param name="num">用来做函数可行性测试,可以不填</param>
|
public Eval(string CharpCode,int num,bool isCommon=false,EvalTemplate me_temp=null)
|
{
|
if (!isCommon)
|
{
|
this.tempCode = EvalTemplate.TempCode_function;
|
code = CharpCode;
|
paramNum = num;
|
tmp = getInstance();
|
if (tmp is string)
|
{
|
isInit = false;
|
errString = tmp.ToString();
|
return;
|
}
|
|
Type type = tmp.GetType();
|
mi = type.GetMethod("myMethod");
|
isInit = true;
|
}
|
else
|
{
|
FunctionIndex = me_temp.Count;
|
CharpCode = TreatHead(CharpCode);
|
me_temp.Add_code(CharpCode);
|
isInit = true;
|
}
|
|
}
|
|
private string TreatHead(string CharpCode)
|
{
|
foreach (var line0 in CharpCode.Split('\n'))
|
{
|
string line = line0.Trim();
|
if (line.ToLower().IndexOf("import") == 0)
|
{
|
string ass = line.ToLower().Replace("import", "").Trim().Trim(';');
|
this.defaultRefs.Add(GlobalPath.configPath + ass);
|
CharpCode = CharpCode.Substring(line0.Length);
|
}
|
else if (line.ToLower().IndexOf("using") == 0)
|
{
|
string ass = line;
|
this.usings.Add(ass);
|
CharpCode = CharpCode.Substring(line0.Length);
|
|
}
|
else
|
{
|
break;
|
}
|
}
|
|
return CharpCode;
|
}
|
|
public Eval(string code)
|
{
|
this.tempCode = null;
|
this.code = code;
|
//paramNum = num;
|
tmp = getInstance();
|
if (tmp is string)
|
{
|
isInit = false;
|
errString = tmp.ToString();
|
return;
|
}
|
isInit = true;
|
|
}
|
/// <summary>
|
/// 构造
|
/// </summary>
|
/// <param name="CharpCode">函数的代码段</param>
|
/// <param name="tempCode"></param>
|
public Eval(string CharpCode, string tempCode=null)
|
{
|
CharpCode = TreatHead(CharpCode);
|
this.tempCode = tempCode;
|
code = CharpCode;
|
//paramNum = num;
|
tmp = getInstance();
|
if (tmp is string)
|
{
|
isInit = false;
|
errString = tmp.ToString();
|
return;
|
}
|
|
Type type = tmp.GetType();
|
mi = type.GetMethod("myMethod");
|
isInit = true;
|
|
}
|
|
public List<string> defaultRefs = new List<string>()
|
{
|
"system.dll"
|
,"Microsoft.CSharp.dll"
|
,"System.Data.dll"
|
,"System.Windows.Forms.dll"
|
,"Microsoft.VisualBasic.dll"
|
,"System.Management.dll"
|
,"System.Drawing.dll"
|
|
,"System.Runtime.dll"
|
,"System.Collections.dll"
|
,"System.Linq.dll"
|
,GlobalPath.Path+ "Hydro.CommonBase.dll"
|
//,GlobalPath.Path+ "Hydro.CodeProvider.dll"
|
//,Directory.GetCurrentDirectory()+"\\"+ "CommonBase.dll"
|
//,Directory.GetCurrentDirectory() + "\\" + "CodeProvider.dll"
|
// ,Directory.GetCurrentDirectory() + "\\" + "HydraulicModel.dll"
|
};
|
|
/// <summary>
|
/// 返回函数进行调用,调用方式resultMehodInfo.Invoke(tmp, null)
|
/// </summary>
|
/// <param name="CharpCode"></param>
|
/// <returns></returns>
|
private object getInstance()
|
{
|
var d = new Dictionary<string, string>() {
|
{ "CompilerVersion", "v4.0" },
|
};
|
CodeDomProvider csharpCodeProvider= CodeDomProvider.CreateProvider("CSharp", d);
|
ICodeCompiler compiler = csharpCodeProvider.CreateCompiler();
|
|
CompilerParameters cp = new CompilerParameters();
|
|
|
defaultRefs.ForEach(refs => cp.ReferencedAssemblies.Add(refs));
|
|
cp.CompilerOptions = $"/t:library /platform:anycpu /optimize+";
|
|
cp.GenerateInMemory = true;
|
|
|
StringBuilder sourceCode = new StringBuilder();
|
|
//return paramArray[0] + paramArray[1] * 3 + paramArray[2];
|
if (tempCode!=null)
|
{
|
sourceCode.Append(tempCode.Replace("{0}", code));
|
}
|
|
else
|
{
|
sourceCode.Append(code);
|
}
|
//myCode.Append("}\r\n");
|
|
CompilerResults cr = compiler.CompileAssemblyFromSource(cp, sourceCode.ToString());
|
if (cr.Errors.Count > 0)
|
{
|
string errString = "";
|
foreach(var err in cr.Errors)
|
{
|
errString += err.ToString()+"\r\n";
|
}
|
return $"{errString}<=====>{sourceCode}";
|
}
|
|
Assembly assembly = cr.CompiledAssembly;
|
|
object tmp = assembly.CreateInstance("CoustomEval.myLib");
|
|
return tmp;
|
|
|
|
|
|
|
|
}
|
|
/// <summary>
|
/// 返回函数进行调用,调用方式resultMehodInfo.Invoke(tmp, null)
|
/// </summary>
|
/// <param name="paramArray"></param>
|
/// <returns></returns>
|
public double getResult(List<double> paramArray, List<double[]> patternArray=null,LogicModelParams param=null,GeneticParams gParam=null)
|
{
|
double result;
|
result = (double)mi.Invoke(tmp, new object[] { paramArray, patternArray, param, gParam });
|
//result = paramArray.Count();
|
return result;
|
//return mi;
|
|
}
|
|
public dynamic ChangeParam(LogicModelParams param, WdnmoParam wParam,GeneticParams gParam,calcParam cParam)
|
{
|
if (mi == null || tmp == null) return null;
|
dynamic r = (mi.Invoke(tmp, new object[] { param, wParam, gParam, cParam }));
|
return r;
|
}
|
//public dynamic ChangeResult(LogicModelParams param, WdnmoParam wParam,GeneticParams gParam,List<Result> results)
|
//{
|
// return ( mi.Invoke(tmp, new object[] { param, wParam, gParam, results }));
|
//}
|
/// <summary>
|
/// 返回函数进行调用,调用方式resultMehodInfo.Invoke(tmp, null)
|
/// </summary>
|
/// <param name="paramArray"></param>
|
/// <returns></returns>
|
public dynamic getResult(Dictionary<string, Dictionary<string, double>> dict_param)
|
{
|
object result = mi.Invoke(tmp, new object[] { dict_param });
|
|
return result;
|
//return mi;
|
|
|
}
|
|
/// <summary>
|
/// 返回函数进行调用,调用方式resultMehodInfo.Invoke(tmp, null)
|
/// </summary>
|
/// <param name="paramArray"></param>
|
/// <returns></returns>
|
public dynamic getResult(dict<string,dict> dict_node, dict<string, dict> dict_link)
|
{
|
object result = mi.Invoke(tmp, new object[] { dict_node,dict_link });
|
|
return result;
|
//return mi;
|
|
|
}
|
|
|
/// <summary>
|
/// 返回函数进行调用,调用方式resultMehodInfo.Invoke(tmp, null)
|
/// </summary>
|
/// <param name="paramArray"></param>
|
/// <returns></returns>
|
public string checkMethod()
|
{
|
Random rand = new Random();
|
List<double> paramArray = new List<double>();
|
for(int i=0;i<paramNum;i++)
|
{
|
paramArray.Add(rand.NextDouble());
|
}
|
|
|
try
|
{
|
object result = mi.Invoke(tmp, new object[] { paramArray.ToArray() });
|
if (!(result is double))
|
{
|
return "函数值的返回类型错误";
|
}
|
}
|
catch(Exception e)
|
{
|
return e.Message;
|
}
|
|
|
|
return null;
|
//return mi;
|
}
|
}
|
public class EvalTemplate
|
{
|
public static Regex GetMyFuncRegex(string funcName)
|
{
|
string text = get转义String(funcName);
|
|
return new Regex(@"(\{\|?)(" + text + @")(\[[0-9]+\]|)(\|?\})");
|
}
|
|
public static string get转义String(string funcName)
|
{
|
string text = funcName;
|
string replaceSign = @"\*.?+$^[](){}|/";
|
for (int i = 0; i < replaceSign.Length; i++)
|
{
|
text = text.Replace(replaceSign[i].ToString(), "\\" + replaceSign[i]);
|
}
|
|
return text;
|
}
|
|
public static Regex FuncRegex = new Regex(@"\{\|?((#|[^\[\]\{\}\|;\s])+)(\[([\-\+][0-9]+|[0-9]+)?\])?\|?\}"); //new Regex( @"\{[\u4E00-\u9fa5A-Za-z0-9_~!@#$%\^&*\(\)()\[\]!@¥……\-\+\|]+\}");
|
public static string FuncRegexString = @"^[^\[\]\{\}\|;\s]+$";
|
|
public static string CommonUse = @"
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Text;
|
using System.IO;
|
using System.Linq;
|
using System.Drawing;
|
|
using Hydro.CommonBase;
|
";
|
public static string TempCode_function = CommonUse+ @"
|
namespace CoustomEval
|
{
|
[Serializable]
|
class myLib
|
{
|
public double myMethod(List<double> paramArray,List<double[]> patternArray,LogicModelParams param=null,GeneticParams gParam=null)
|
{
|
{0}
|
}
|
}
|
}";
|
|
static string TempCode_Total = CommonUse + @"
|
namespace CoustomEval
|
{
|
[Serializable]
|
class myLib
|
{
|
{0}
|
}
|
}";
|
static string functionTemp = @"
|
public double TMethod{1}(List<double> paramArray,List<double[]> patternArray,LogicModelParams param=null,GeneticParams gParam=null)
|
{
|
{0}
|
}";
|
|
public static string helpText_Set =
|
@"
|
[类型说明]
|
dict:字典类对象,等价于dictionary<string,object>
|
[变量说明]
|
dict map :引用节点类对象集合
|
dict map_link :链接类对象集合
|
|
[属性使用示例]
|
obj[""type""] as string==""JUNCTION""
|
obj[""EN_ELEVATION""] as float==0.1f
|
|
[示例]
|
dict re = new dict();
|
foreach (var m in map)
|
{
|
string id = m.Key;
|
dict obj = m.Value as dict;
|
if (obj[""type""] as string==""JUNCTION"" && obj[""otype""] as string ==""Meter"")
|
re.Add(id, obj);
|
}
|
return re;
|
|
|
//节点属性清单
|
type //类型 JUNCTION RESERVOIR TANK
|
otype //子类型 JUNCTION METER NOZZLE RESERVOIR TANK
|
EN_ELEVATION //标高
|
EN_BASEDEMAND //基本需水量
|
EN_PATTERN //模式
|
EN_EMITTER //射流系数
|
EN_INITQUAL //初始水质
|
EN_SOURCEQUAL
|
EN_SOURCEPAT
|
EN_SOURCETYPE
|
EN_TANKLEVEL
|
EN_DEMAND
|
EN_HEAD
|
EN_PRESSURE
|
EN_QUALITY
|
EN_SOURCEMASS
|
EN_INITVOLUME
|
EN_MIXMODEL
|
EN_MIXZONEVOL
|
|
//节点管线清单
|
type //类型 CVPIPE PIPE PUMP PRV PSV PBV FCV TCV GPV
|
otype //子类型 CVPIPE PIPE PUMP PRV PSV PBV FCV TCV GPV
|
EN_DIAMETER
|
EN_LENGTH
|
EN_ROUGHNESS
|
EN_MINORLOSS
|
EN_INITSTATUS
|
EN_INITSETTING
|
EN_KBULK
|
EN_KWALL
|
EN_FLOW
|
EN_VELOCITY
|
EN_HEADLOSS
|
EN_STATUS
|
EN_SETTING
|
EN_ENERGY
|
";
|
public static string helpText_Function =
|
$@"
|
=======[对象说明]======
|
Values:用来存储多个时刻的计算结果值,单时刻计算值,长度为1;多时刻计算时,长度为时段数;
|
LogicValues:通常用来存储多个时刻的设置值,初始长度模式与Values一致;也可以作为曲线使用,使用数据来源为模式系数的选项,将一段自定义曲线存入;
|
|
|
=======[引用对象的方法]======
|
①一般使用""{{标签}}""或""{{变量名称}}""来引用变量,标签和变量名称有重复时,优先判定为标签;返回的是double类型。变量的值取决于变量的数据来源决定;
|
②获取数组和数组中的值:
|
-使用""{{标签[]}}""来引用变量的LogicValues,返回double[]类型。
|
-使用""{{标签[i]}}""来获取变量的LogicValues中的第i个值,返回double类型。
|
-使用""{{标签[-/+i]}}""来获取过去或未来时刻的值,返回double类型。例如{{标签[-1]}}表示获取上一时刻的值,{{标签[+1]}}表示获取下一时刻的值。
|
③同样的,用""{{标签<>}}""、""{{标签<i>}}""、""{{标签<-/+i>}}""来获取Values的相关值。
|
|
语法说明:
|
编译环境为.netframework4.0,支持的语法如下:
|
类型转换建议使用Convert.ToDouble(),例如""Convert.ToDouble(变量名称)"",或者""变量名称 as T""
|
|
|
程序集框架构造如下,需要填写{{0}}中的内容:
|
{EvalTemplate.TempCode_function}
|
";
|
public static string helpText_Model =
|
$@"
|
使用""{{变量名称}}""来引用变量,返回的是double类型。例如""{{XX流量}}""引用变量XX流量,变量的值取决于变量的数据来源
|
使用""{{变量名称[]}}""来引用变量的LogicPattern,返回double[]类型。
|
使用""{{变量名称[i]}}""来获取变量的LogicPattern中的第i个值,返回double类型。
|
编译环境为.netframework4.0,支持的语法如下:
|
类型转换建议使用Convert.ToDouble(),例如""Convert.ToDouble(变量名称)"",或者""变量名称 as T""
|
|
|
|
程序集框架构造如下,需要填写{{0}}中的内容:
|
{EvalTemplate.TempCode_PreTreat}
|
";
|
|
List<string> codes_Total = new List<string>();
|
|
public int Count { get { return codes_Total.Count; } }
|
|
public void Add_code(string code)
|
{
|
string Fcode = functionTemp.Replace("{0}", code).Replace("{1}",codes_Total.Count.ToString());
|
//对于Fcode中每一行的缩进进行处理
|
var arr = Fcode.Replace("\r\n","\n").Split('\n');
|
for(int i=3; i<arr.Length-1; i++)
|
{
|
//if (arr[i].StartsWith(" "))
|
//{
|
// //arr[i] = arr[i].Substring(4);
|
//}
|
//else if (arr[i].StartsWith(" "))
|
//{
|
// arr[i] = " " + arr[i];
|
//}
|
//else
|
{
|
arr[i] = " " + arr[i];
|
}
|
}
|
Fcode = string.Join("\r\n", arr);
|
codes_Total.Add(Fcode);
|
}
|
|
public string Get_code()
|
{
|
string fCodes= string.Join("\r\n",codes_Total.ToArray());
|
return TempCode_Total.Replace("{0}",fCodes);
|
}
|
|
public void Clear()
|
{
|
codes_Total.Clear();
|
}
|
public static void fi()
|
{
|
|
}
|
|
public static string TempCode_Set = CommonUse+ @"
|
namespace CoustomEval
|
{
|
[Serializable]
|
class myLib
|
{
|
public dict<string,dict> myMethod(dict<string,dict> map_node,dict<string,dict> map_link)
|
{
|
{0}
|
}
|
}
|
}
|
";
|
public static string TempCode_PreTreat = CommonUse+@"
|
namespace CoustomEval
|
{
|
[Serializable]
|
class myLib
|
{
|
public object myMethod(LogicModelParams param, WdnmoParam wParam,GeneticParams gParam,calcParam cParam)
|
{
|
{0}
|
}
|
}
|
}
|
";
|
}
|
|
}
|