今天介紹一下如何在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/
關於變量賦值,若是有老鐵解決了,歡迎留言。