侧边栏壁纸
博主头像
陌上花 博主等级

回首万事皆休

  • 累计撰写 69 篇文章
  • 累计创建 11 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

CSharp and python and C++

种向日葵的人
2024-08-30 / 0 评论 / 0 点赞 / 20 阅读 / 0 字

CSharp调用python

Why

  • 因为公司最近有这一部分的需求,所以我这边挺感兴趣也就打算看一看。其实总结来说使用C#调用Python是一件非常简单的事情,因为python本身就是跨平台的,所以其实直接在调用处配置一份python的环境不就可以了,然后C#开个进程直接调用环境的python.exe来执行某个py文件不就行了呗。不要跟我扯什么一些包例如ironpython啊啥的,那玩意儿根本就不稳定,我之前试的就是各种配置杂乱然后还是要安装包,没啥区别的好吧。

How

  • 因为后续会使用C++来调用C#,所以这里需要建立C#的类库项目。代码如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LaserLib
{
    public class PQLib
    {
        public string Start(string dt1, string dt2)
        {
            var pyPath = $@"{AppDomain.CurrentDomain.BaseDirectory}dllpython.py";
            var pyExe = $@"{AppDomain.CurrentDomain.BaseDirectory}Python37\python.exe";

            // 要传递给Python脚本的参数
            //string dt1 = "效率优先";
            //string dt2 = "3";

            var process = new ProcessStartInfo()
            {
                FileName = pyExe,
                Arguments = $"{pyPath} {dt1} {dt2}",
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
            };
            var msg = string.Empty;
            using (var proc = Process.Start(process))
            {
                proc?.WaitForExit();
                var output = proc?.StandardOutput.ReadToEnd();
                var error = proc?.StandardError.ReadToEnd();

                msg = string.IsNullOrWhiteSpace(output) ? error : output;
                //Console.WriteLine(output);
                //Console.WriteLine(error);
            }

            return msg;

        }
    }
}
  • 同时给大家看看我的项目下的样式。
    C#类库目录.png
  • 可以看到是直接把完整的python环境拿到生成目录下的,当然这个只是生成类库,所以没有exe。请看下方继续使用C++调用C#的方法。
  • 注意当前项目生成一定要切换成x64的,后续才能成功。

C++调用CSharp

  • 以下简单说一下如何使用C++调用CSharp的上述生成的类库。

How

  • 你需要新建一个有关于C++win32的空项目,然后点击这个项目设置属性。属性->配置属性->高级->公共语言运行时配置为clr,请注意这是必须的同时也是很重要的。
    C++配置C#属性.png
  • 然后添加一个cpp文件,同时在里面书写如下代码。
using namespace std;
#include <iostream>
#include <tchar.h>
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
//注意:需要将LaserLib.dll放到当前目录下
//注意:此处需要使用绝对路径指定生成的dll 但是好像设置C++的包含目录也是可以的 不过因为只是测试的,所以我直接使用的绝对路径,其余的可以自行尝试吧
#using "C:\Users\10335\Desktop\peng\work\demo\CSharpToPython\src\LaserLib\bin\Debug\LaserLib.dll"
using namespace System;
using namespace msclr::interop;

int _tmain(int argc, _TCHAR* argv[])
{
	LaserLib::PQLib^ pq = gcnew LaserLib::PQLib();
	System::String^ dt1 = "效率优先";
	System::String^ dt2 = "2";
	auto msg = pq->Start(dt1, dt2);
	string result = marshal_as<std::string>(msg);
	std::cout << result << endl;
	return 0;
}
  • 同时你也需要将上述的python环境和需要的py文件复制到生成的目录下,如果不出意外的话你这个时候就会出出现你想要的结果了。

Tips

  • 使用上述方式在三方之间调用的时候需要注意的是,你所使用的py文件中如果涉及到文件的操作,例如打开当前目录下的某个文件,别人可能是偷懒直接使用joblib.load(f'OneHot_model.pkl'),这种方式使用python执行时没问题的,但是一旦三者串联起来就会显示找不到文件了,所以正确的写法应该如下:
curDir = sys.path[0]
d1 = joblib.load(f'{curDir}\\OneHot_model.pkl')
  • 注意程序中的文件路径中一定不要出现空格,例如a b这种,不然无法找到python.exe
  • 三方调用基本是可以打通的,而且其实都不是很难,没有特别多的操作,只不过很多地方需要细心一点就行了。Ok,Have Fun!
0
博主关闭了所有页面的评论