最近做U3D的热更新,研究了各种方式无果后,最容易最先想到的方式就是利用c#的反射机制,动态加载代码,但是由于ios上aot的限制,导致ios上不能实现,最后 找到了cslight这个东西,可以在一定范围内动态编译执行cs代码。项目主页http://crazylights.cnblogs.com/ github 主页https://github.com/lightszero/CSLightStudio,这个cslight的作者还是很厉害的,利用这个东西成功的将项目中策划配表等容易经常变动的地方实现了动态编译执行,下面总结下对cslight的理解和使用心得。
1.首先cslight支持部分的c#代码,支持情况包括
项目 | 支持 | 不支持 |
注释 | 支持// | 不支持 /* */ |
基本类型 | 支持int uint bool string float double | 不支持byte char short 等,但可以扩展 |
变量和定义 | 同c#定义变量方式,先定义再使用,可以在定义同时赋值。 例 int i; | |
数学计算 | 同c# 支持 + - * / % 五种数学计算 支持 += -= /= *= %= 五种自运算 支持 ++ -- 两种自增运算,只支持变量在左侧 ++i 不支持 i++ 支持 支持 > >= < <= != == && || 八种逻辑运算 支持! 取反 支持三目运算?: | 不支持位运算 |
循环 | 支持 for foreach while dowhile,支持continue,break,return 支持 if,可以if else嵌套 | 不支持switch goto |
命名空间 | 可以写 Debug.Log(); 不可以写 UnityEnging.Debug.Log(); C#Evil 头部可以写using | 不支持 |
对象调用 | 注册了类型以后 new 支持 as 和 强制类型转换 支持 成员变量访问支持 成员函数调用支持 向类型注册事件代理支持 支持对象的[] index访问 静态支持 C#Evil 可以在脚本里编写class | 脚本里编写的class 不能继承 |
数组 | 数组完整支持 支持 new int[3] new int[]{1,2,3} 两种语法 任何类型数组都必须注册子类型和数组类型 泛型数组 作为类型支持 比如可以将List<int> Dictionary<int,string> 注册成一个类型总体使用 | |
泛型 | 支持 List<int> 作为一个类型不能有空格 例如 List < int > 就不认识了 | |
委托 | 支持脚本编写函数注册给程序的委托接口 A.Test+=Func1; A.SetTest(Func1); 两种形式 | |
匿名函数 | 支持lambda表达式 可以给委托赋值 | 不支持 将lambda 表达式赋值给var变量 |
异常处理 | 支持 | |
继承 | 可以继承脚本中编写的interface,可以多继承 | 不支持class继承(是因为IOS 上aot的缘故) |
get/set | 只支持自动实现 int i { get; set; } | 不支持编写get/set过程 |
|
2.基本的程序(cs)和脚本(cslight)之间的关系
3.使用步骤
1)new一个environment
CLS_Environment env=new CLS_Environment(this);
2)注册引擎的类给脚本,如env.RegType(new CSLE.RegHelper_Type(typeof(List<string>),"List<string>"));
3)编译脚本
Dictionary<string, IList<Token>> project = new Dictionary<string, IList<Token>>();
List<string> csPaths=new List<string>();
List<byte[]> bytes=new List<byte[]>();
for(int i=0;i<bytes.Count;i++){
IList<Token> tokens =env.ParserToken( CommonTool.Bytes2String(bytes[i],enc));
project.Add(csPaths[i],tokens);
}
env.Project_Compiler(project,true);
4)动态的执行代码
CLS_Content content=env.CreateContent();
IList<Token> runCodetokens = env.ParserToken(code);
CLS_Content.Value value=null;
try
{
ICLS_Expression expr = env.Expr_CompilerToken(runCodetokens);
value= env.Expr_Execute(expr, content);
}
catch (Exception err) {
Debug.LogError( string.Format("cs light run error dump:\n {0} {1} {2}",content.DumpValue(),content.DumpStack(null),err.ToString()));
}
return value;
C#Light能够有权限调用的类型需要提前注册
委托的注册稍微不太一样
env.RegDeleType(new CSLE.RegHelper_DeleAction("Action"));
调试错误
1.打Log进行判断
2.只需要在运行脚本时try一下,出错以后用content.DumpValue 可以Dump出脚本堆栈上的变量值
content.DumpStack 可以Dump出脚本执行堆栈
再加上异常本身反馈的信息