IronPython for C#(五)

通常情况下,是将C#代码共享到python脚本中,可以通过脚本调用C#的各个对象。

 

一、IronPythonRunner

创建IronPython运行器,可通过该运行器运行python脚本。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using IronPython.Compiler;
using IronPython.Hosting;
using IronPython.Runtime;

using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Hosting.Providers;
using Microsoft.Scripting.Runtime;

namespace IronPythonTest
{
    internal class IronPythonRunner
    {
        public ScriptEngine Engine { get; set; }
        ScriptScope _scope;

        public IronPythonRunner()
        {
            Dictionary<string, object> options = new Dictionary<string, object>();
            options["LightweightScopes"] = true;
            Engine = Python.CreateEngine(options);
            List<string> collectionStr = new List<string>();
            collectionStr.Add(AppDomain.CurrentDomain.BaseDirectory);

            //导入python库,若在脚本中不使用python库,可以不导入
            string[] libPaths = new string[]
            {
               Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"IronPythonLib"),  //
               @"C:/Program Files (x86)/IronPython 2.7/Lib",               // IronPython installed on PC (32 bit)
               @"C:/Program Files/IronPython 2.7/Lib",                      // IronPython installed on PC (64 bit)
            };

            for (int i = 0; i < libPaths.Length; i++)
            {
                DirectoryInfo di = new DirectoryInfo(libPaths[i]);
                if (di.Exists)
                {
                    collectionStr.Add(libPaths[i]);
                    break;
                }
            }
            Engine.SetSearchPaths(collectionStr);
            _scope = Engine.CreateScope();
        }

        private void AddSearchPaths(string fullFilePath)
        {
            ICollection<string> paths = Engine.GetSearchPaths();
            if (!paths.Contains(fullFilePath))
            {
                string direPath = Path.GetDirectoryName(fullFilePath);
                if (!string.IsNullOrWhiteSpace(direPath))
                {
                    paths.Add(direPath);
                    Engine.SetSearchPaths(paths);
                    DirectoryInfo directory = new DirectoryInfo(direPath);
                    foreach (var path in directory.GetDirectories())
                    {
                        AddSearchPaths(path.FullName);
                    }
                }
            }
        }

        public dynamic RunScriptByPath(string fullFilePath)
        {
            AddSearchPaths(fullFilePath);
            ScriptSource source = Engine.CreateScriptSourceFromFile(fullFilePath);
            return RunScript(source);
        }

        public dynamic RunScriptByString(string pythonCodeStr)
        {
            ScriptSource source = Engine.CreateScriptSourceFromString(pythonCodeStr);
            return RunScript(source);
        }

        private dynamic RunScript(ScriptSource source)
        {
            PythonCompilerOptions pco = (PythonCompilerOptions)Engine.GetCompilerOptions(_scope);
            pco.ModuleName = "__main__";
            pco.Module |= ModuleOptions.Initialize;
            CompiledCode code = source.Compile(pco);
            return code.Execute(_scope);
        }

        public void ShareVariableToScript(string name, object value)
        {
            IEnumerable<string> variables = _scope.GetVariableNames();
            if (!variables.Contains(name))
            {
                _scope.SetVariable(name, value);
            }
        }

        public Scope CustomImportModule(string moduleName, string scriptPath)
        {
            string rawScript = File.ReadAllText(scriptPath);
            ScriptScope scopetemp = Engine.CreateScope();
            var varNames = scopetemp.GetVariableNames();
            foreach (var kv in _scope.GetItems())
            {
                if (!varNames.Contains(kv.Key) && kv.Value != null)
                {
                    scopetemp.SetVariable(kv.Key, kv.Value);
                }
            }
            Engine.Execute(rawScript, scopetemp);
            Scope ret = HostingHelpers.GetScope(scopetemp);
            _scope.SetVariable(moduleName, ret);
            return ret;
        }

    }
}

 二、PythonModel

创建要传入python脚本的类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IronPythonTest
{
    public class PythonModel
    {
        public event Action<string> SendMessageEvent;
        public event Func<List<int>, int?> AddEvent;

        public string Name { get; set; }

        public int? Add(int a, int b)
        {
            return AddEvent?.Invoke(new List<int> { a, b });
        }

        public void GetValue(ref float arg1, out float? arg2, out List<int> arg3)
        {
            arg1 = 3.4f;
            arg2 = null;
            arg3 = new List<int> { 1, 3 };
            SendMessageEvent?.Invoke($"GetValue:arg1 = {arg1},arg2 = {arg2},arg3 = {string.Join(",", arg3)}");
        }

        public void SetValue(int[] arg1)
        {
            SendMessageEvent?.Invoke($"SetValue:{string.Join(",", arg1)}");
        }
    }
}

三、Program

创建控制台程序,实例化IronPythonRunner,并将PythonModel对象传入脚本中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IronPythonTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            PythonModel pythonModel = new PythonModel();
            IronPythonRunner runner = new IronPythonRunner();
            runner.ShareVariableToScript("VM", pythonModel);
            runner.ShareVariableToScript("WL", new Action<string>((str) =>
            {
                Console.WriteLine(str);
            }));
            runner.RunScriptByPath("test.py");
            Console.ReadKey();
        }
    }
}

四、test.py

创建test.py脚本

# !/usr/bin/python
# -*- coding: UTF-8 -*-

import System   #导入C#的系统库System
import clr

clr.AddReference('IronPython.dll')  #导入非系统的dll
from IronPython.Compiler import PythonOperator  #从非系统的dll中导入相关对象

from System import Array
from System.Collections.Generic import List

#获取代码传送到脚本的变量
vm = globals().get('VM')
wl = globals().get('WL')

#当然也可以直接使用
WL('Start')

wl(str(PythonOperator.Power))

def writeline(str):
    wl(str)

def add(lista):
    res = 0
    for a in lista:
        res += a
    wl('res = ' + str(res))
    return res

#订阅事件
vm.SendMessageEvent += writeline   
vm.AddEvent += add;

vm.SetValue(Array[int]([3,2,1]))   #定义一个整型数组

vm.Add(2,3)

#对应ref或out参数,需用clr.StrongBox定义
arg1 = clr.StrongBox[System.Single]()                    #定义强类型float
arg2 = clr.StrongBox[System.Nullable[System.Single]]()   #定义强类型float?
arg3 = clr.StrongBox[List[System.Int32]]()               #定义强类型List<int>
vm.GetValue(arg1, arg2, arg3)

 

posted @ 2022-08-24 15:09  Bridgebug  阅读(224)  评论(0编辑  收藏  举报