今天介绍一下如何在C#侧调用Python脚本,而且作一些有趣的实验。html
首先介绍一下今天的主角,IronPython,大名鼎鼎,想要了解的能够去它的官网看看相关的介绍,很带劲。http://ironpython.net/python
新建一个C#的控制台项目,而后使用nuget安装这个IronPython组件数组
Install-Package IronPython
好了,开始学习吧。网络
首先咱们须要理解,为何会需求脚本?没有脚本行不行?固然行啊!可是咱们能够想象一下一个需求。咱们从设备获取到了一个数据,好比是 float a = 100f; 可是这个数不是最终的数,而是须要运算的,好比是要缩小10倍才是正确的数。学习
那么咱们会 a = a / 10; 若是业务变成了会缩小N倍,这个倍数不必定,常常会调整。好了,咱们就把这个倍数作成了配置项,保存在txt里,而后从txt加载倍数,而后来动态调整,这时候咱们的程序已经很灵活了。.net
在txt里写入 10 就是缩小10倍,写入0.5就是放大两倍。OK,如今业务变得更加的复杂了!我不必定是乘除法,也多是加减法,甚至是组合运算加减乘除法。这时候你会怎么作呢?线程
传统的方式,我仍是作配置文件,把每种状况都罗列出来,1表明乘除法,2表明加减法,3表明什么什么,等等,每种状况再作配置文件,配置项不同嘛。这种方式固然也能够实现,只是debug
1. 比较麻烦,须要写大量的配置代码,读写文件的代码。3d
2. 仍然适应不了将来的变化,之后可能业务又更改了,而你一开始没有考虑到,又要改源代码了,而后编译,而后部署。code
ok,如今能够尝试一种全新的技术(其实脚本技术不算新),这里的新技术主要是对于刚接触的人来讲。
咱们针对上面的需求进行实现。
咱们如今程序的debug目录下,新建一个hsl.py文件,方便咱们的调用,而后咱们使用VS CODE 进行编辑这个文件,关于如何安装python及配置环境啥的,能够参考下面的文章:
https://www.cnblogs.com/dathlin/p/12142663.html
好了,如今开始编辑了,咱们须要定义一个转换的方法,以下所示
而后咱们在C#里写下面的代码
static void Main( string[] args ) { float value = 123f; // 模拟咱们获取到的数据 Microsoft.Scripting.Hosting.ScriptEngine engine = IronPython.Hosting.Python.CreateEngine( ); dynamic script = engine.ExecuteFile( "hsl.py" ); float result = script.GetActulValue( value ); Console.WriteLine( $"Value Old:{value} New Value:{result}" ); Console.ReadLine( ); }
咱们运行起来看看,看看会输出什么?
这时候应该发出震撼的声音,我去!竟然真的能够,咱们在看看修改下python脚本的代码
看看结果
上述的例子太简单了,咱们来看看更高级的数学方法
咱们改的更高级一点了。这个数能够算出啥。我也不知道了。因此咱们看看,这玩意能输出什么?
emmmmm.....报错了,python的运算以后结果变成了double类型,应该是math处理方法的缘由,因此咱们的C#代码要万无一失的话,稍微改改
好了,看来咱们能够用一些python本身的库相关的代码,均可以执行。接下来咱们看看下面的py代码
咱们看看这个效果
这么看来也是没有任何问题的。
这样的话,就能够完成一些很高级的自定义的脚本操做了。
你觉得到这里就结束了?接下来才是给力的部分。上述已经实现了文章开篇提出的需求了,接下来咱们看看一个更高级的需求。
在C#里有五个方法。A,B,C,D,E表明了业务的五个部分,咱们的主体业务是分别调用这五个方法,进行排列组合,甚至,有的不执行,或是执行屡次。若是须要这种业务应该怎么办呢?
一样是脚本是最合适,咱们须要在python里调用C#的这五个方法。
那么第一步就是定义这五个方法
public static void A( ) { Console.WriteLine( "Method A Called" ); } public static void B( ) { Console.WriteLine( "Method B Called" ); } public static void C( ) { Console.WriteLine( "Method C Called" ); } public static void D( ) { Console.WriteLine( "Method D Called" ); } public static void E( ) { Console.WriteLine( "Method E Called" ); }
很简单,只要被调用一次,就会打印出记录,方便咱们跟踪。
static void Main( string[] args ) { Microsoft.Scripting.Hosting.ScriptEngine engine = IronPython.Hosting.Python.CreateEngine( ); Microsoft.Scripting.Hosting.ScriptScope scope = engine.CreateScope( ); scope.SetVariable( "A", new Action( A ) ); scope.SetVariable( "B", new Action( B ) ); scope.SetVariable( "C", new Action( C ) ); scope.SetVariable( "D", new Action( D ) ); scope.SetVariable( "E", new Action( E ) ); engine.ExecuteFile( "hsl.py", scope ); Action business = scope.GetVariable<Action>( "MainBusiness" ); business( ); // 调用主业务现实 Console.ReadLine( ); }
这里咱们不用C#的动态语法来执行脚本了,咱们经过获取委托的方式,固然了,咱们先把这五个方法,传进python里面去,就能够调用了,python的代码以下,须要注意的是,方法名和上面的要同样
ok,很简单的,就是顺序调用一下而已,好了,咱们如今看看输出
我去,真的能够啊,牛逼,不由再次感叹下,来来来,咱们的脚本写的更加复杂点。
咱们还加入的循环体,来来来,继续看看效果。
我去,牛逼!!!
再来看看变量呢?
咱们新增长一个count变量,而后传入到python脚本,看看python能不能获取到
而后咱们运行C#侧的代码
能够获取到,咱们如今来更改值看看
就是简单的修改一个值。
发现没有更新,那么能够推断,传入Python的值变量,只是数据的副本,那么咱们应该传入引用变量
咱们定义了一个匿名类型,若是这部分不清楚,就能够去补补C#的知识了。
好了,咱们再运行看看
额,,,,发生异常了。这里暂时尚未想明白,不过暂时的解决能够经过返回值来解决,咱们让业务方法返回数据,进行更改。若是有网友知道怎么解决,很是感谢。
运行看效果。
OK,最后咱们来看看,若是我还有一个py的脚本文件。实现另外一个方法,F()
我须要在上面的脚本里调用这个方法。
咱们同时加载第二个文件,而后更改第一个py文件的代码
而后咱们看运行效果。
ok,能够,很是好,剩下的细节就要结合实际开发了。接下来看一个例子:
咱们在项目里面安装 HslCommuncation
咱们在C#的代码里生成一个链接西门子的网络对象类。而且把这个类传递给Python,那么代码以下所示:
static void Main( string[] args ) { var data = new Good (){ Name = "BooK", Price = 10 }; Microsoft.Scripting.Hosting.ScriptEngine engine = IronPython.Hosting.Python.CreateEngine( ); Microsoft.Scripting.Hosting.ScriptScope scope = engine.CreateScope( ); scope.SetVariable( "Good", data ); scope.SetVariable( "A", new Action( A ) ); scope.SetVariable( "B", new Action( B ) ); scope.SetVariable( "C", new Action( C ) ); scope.SetVariable( "D", new Action( D ) ); scope.SetVariable( "E", new Action( E ) ); HslCommunication.Profinet.Siemens.SiemensS7Net siemens = new HslCommunication.Profinet.Siemens.SiemensS7Net( HslCommunication.Profinet.Siemens.SiemensPLCS.S1200, "192.168.8.12" ); siemens.SetPersistentConnection( ); scope.SetVariable( "siemens", siemens ); engine.ExecuteFile( "hsl.py", scope ); engine.ExecuteFile( "hsl2.py", scope ); Func<int> business = scope.GetVariable<Func<int>>( "MainBusiness" ); data.Price = Convert.ToInt32(business( )); // 调用主业务现实 Console.WriteLine( data.Price.ToString( ) ); siemens.ConnectClose( ); Console.ReadLine( ); }
而后在python里读取西门子的数据信息。而后打印出来
ok,那么咱们来执行
能够,很是给力。
咱们再来看看写入操做。
读出来是0,应该是写入的类型不对,那么咱们须要写入的是short类型,应该怎么操做呢?
这样就能够读取到咱们须要的数据了。若是咱们写入的是数组呢?
咱们天然而然想到:
结果报下面的错误。
意思就是两个重载的方法不知道选哪一个,好了,问题知道了,咱们来修复下这个内容
到这里成功写入,咱们也拿到了本身的数据。
若是我须要使用 C#的类,这个类是我本身建立的话。
好比说这里的OperateResult
若是想使用线程的技术,可使用C#的线程技术
from System.Threading import Thread, ThreadStart
def ThreadCheck(): count = 0 while True: count = count + 1 time.sleep(1) logNet.WriteDebug('线程检测:'+ str(count)) if count > 10: break def SendMesCmdToPlc(cmd): Thread(ThreadStart(ThreadCheck)).Start()
就能够启动线程的检测
更详细的英文版教程以下:
https://ironpython.net/documentation/dotnet/
关于变量赋值,若是有老铁解决了,欢迎留言。