如何将C#编写的程序移植到linux平台上

内容分享23小时前发布 PLnaonao
0 0 0

将 C# 程序移植到 Linux 平台的核心是基于跨平台的.NET 运行时(.NET Core/.NET 5+,统称.NET)重构 / 适配代码,因为传统的.NET Framework 仅支持 Windows,而.NET 6/7/8(LTS 版本推荐)是真正跨平台的运行时,可直接在 Linux 上运行 C# 程序。以下是完整的移植流程,包含环境准备、代码适配、编译部署、调试优化,以及针对硬件访问场景的特殊处理(结合你之前关注的硬件调用需求)。

一、前置知识:C# 跨平台的核心前提

技术栈 支持 Linux 说明
.NET Framework(≤4.8) 仅 Windows,必须迁移到.NET
.NET Core 2.1+/NET 5+ 跨平台(Windows/Linux/macOS)
WinForms/WPF 仅 Windows,需替换为跨平台 UI
ASP.NET Core 跨平台 Web 程序,无适配成本
控制台程序 少量适配即可迁移

核心结论:先将项目升级为.NET 6/7/8(推荐.NET 8 LTS),再解决平台特定代码的适配问题。

二、步骤 1:环境准备

1. Windows 端(开发环境)

安装 Visual Studio 2022(或 VS Code):
VS 2022 需勾选「.NET 跨平台开发」组件、「Linux 开发工具」(用于远程调试);VS Code 需安装 C# 插件(OmniSharp)、Remote – SSH 插件(远程调试 Linux)。 安装.NET SDK(跨平台):从微软官网下载.NET 8 SDK(Windows 版本),验证安装:

bash

运行


dotnet --version # 输出8.x.x即成功
2. Linux 端(运行 / 部署环境)

安装.NET SDK / 运行时(按需):

bash

运行



# 以Ubuntu 22.04为例
# 1. 添加微软源
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
 
# 2. 安装.NET 8 SDK(开发用)或运行时(部署用)
sudo apt update
sudo apt install -y dotnet-sdk-8.0 # 开发/编译用
# 或仅安装运行时(部署更轻量)
sudo apt install -y aspnetcore-runtime-8.0 # Web程序
# 或
sudo apt install -y dotnet-runtime-8.0 # 控制台/桌面程序

验证安装:

bash

运行


dotnet --version # 输出8.x.x即成功

三、步骤 2:项目迁移与代码适配

1. 升级项目文件(.csproj)

将传统.NET Framework 的
.csproj
(非 SDK 格式)转换为SDK 格式(跨平台核心),示例对比:

旧格式(.NET Framework 4.8) 新格式(.NET 8)
“`xml

<Project ToolsVersion=”15.0″ xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″><PropertyGroup><TargetFrameworkVersion>v4.8</TargetFrameworkVersion></PropertyGroup><ItemGroup><Reference Include=”System” /></ItemGroup></Project>“` | “`xml<Project Sdk=”Microsoft.NET.Sdk”><PropertyGroup><!– 目标框架:net8.0(跨平台) –><TargetFramework>net8.0</TargetFramework><!– 可选:指定支持的运行时 –><RuntimeIdentifiers>win-x64;linux-x64;linux-arm64</RuntimeIdentifiers></PropertyGroup></Project>“` |

操作方式

VS 2022 中右键项目 → 「升级」→ 选择.NET 8(自动转换项目文件);手动修改:删除旧的
Reference
(SDK 格式自动引用核心库),仅保留必要的 NuGet 包。

2. 代码适配:解决平台特定问题

这是移植的核心,需替换 / 适配 Windows 专属 API,重点关注以下场景:

(1)文件路径与 IO

问题:Windows 用
分隔路径,Linux 用
/
;Windows 的盘符(C:)在 Linux 不存在。解决方案:使用
Path.Combine

Environment.GetFolderPath
等跨平台 API,避免硬编码路径。

csharp

运行



// 错误(硬编码Windows路径)
string path = "C:\data\file.txt";
 
// 正确(跨平台)
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "file.txt");
(2)Windows 专属 API 替换
Windows 专属 API Linux 替代方案

System.Windows.Forms
/
WPF
跨平台 UI 框架:Avalonia、MAUI、GTK#;或改为控制台 /ASP.NET Core Web 程序

Microsoft.Win32.Registry
.NET 5 + 提供兼容版(Linux 下仅支持模拟注册表,或改用配置文件如 appsettings.json)
P/Invoke 到 Win32 DLL(如
kernel32.dll
替换为 Linux 的 SO 库(如
libc.so
),或封装平台适配层(类似之前 C++ 的 HAL 层)

Process.Start(UseShellExecute: true)
Linux 下
UseShellExecute
需设为
false
,否则报错

示例:进程启动适配

csharp

运行



// 跨平台进程启动
var psi = new ProcessStartInfo
{
    FileName = "echo",
    Arguments = "hello linux",
    UseShellExecute = false, // Linux必须设为false
    RedirectStandardOutput = true
};
using var process = Process.Start(psi);
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
(3)硬件访问适配(结合你之前的需求)

如果程序涉及硬件调用(串口 / USB/GPIO),需替换 Windows 专属的硬件库为跨平台版本:

Windows 硬件库 Linux 跨平台替代方案

System.IO.Ports
(.NET Framework)
.NET 5 + 内置
System.IO.Ports
(支持 Linux);或 NuGet 包
SerialPortStream
Win32 API 调用串口 / USB 跨平台 NuGet 包:
LibUsbDotNet
(USB)、
SerialPortStream
(串口);或 P/Invoke 到 Linux 的
libudev.so

示例:跨平台串口访问

csharp

运行



// .NET 8跨平台串口操作(支持Windows/Linux)
using System.IO.Ports;
 
// 枚举串口(Linux下返回/dev/ttyUSB0等,Windows返回COM3等)
string[] ports = SerialPort.GetPortNames();
foreach (var port in ports)
{
    Console.WriteLine($"Found port: {port}");
}
 
// 打开串口(跨平台)
using var serialPort = new SerialPort(ports[0], 9600)
{
    Parity = Parity.None,
    DataBits = 8,
    StopBits = StopBits.One
};
serialPort.Open();
serialPort.Write("Hello Linux!");
string data = serialPort.ReadLine();
serialPort.Close();
(4)依赖库适配

检查 NuGet 包是否支持 Linux:在 NuGet 官网查看包的「支持的目标框架」(需包含
netstandard2.0
/
net6.0
等);移除 Windows 专属 NuGet 包(如
WindowsAPICodePack
),替换为跨平台版本。

3. 移除未使用的 Windows 依赖

删除项目中对 Windows 专属库的引用(如
System.Windows

WindowsBase
),避免编译报错。

四、步骤 3:编译与部署到 Linux

1. 编译方式(2 种)
方式 1:Windows 端编译 Linux 目标

在 VS 2022 或命令行中编译为 Linux 可执行文件:

bash

运行



# 命令行编译(自包含部署:无需Linux安装.NET运行时)
dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish/linux
 
# 框架依赖部署(需Linux安装.NET运行时,体积更小)
dotnet publish -c Release -r linux-x64 --self-contained false -o ./publish/linux


-r
:指定运行时标识符(RID),常见值:
linux-x64
(64 位 x86 Linux)、
linux-arm64
(ARM64 Linux,如树莓派);
--self-contained true
:打包.NET 运行时,Linux 无需预装.NET,体积较大(约 50MB);
--self-contained false
:仅打包程序,Linux 需安装对应.NET 运行时,体积小(几 MB)。

方式 2:Linux 端直接编译

将源码复制到 Linux,执行编译命令:

bash

运行



# 克隆/复制源码到Linux目录
cd /home/yourname/yourproject
# 编译并发布
dotnet publish -c Release -r linux-x64 -o ./publish
2. 部署到 Linux

复制
publish
目录到 Linux(通过 SCP/FileZilla 等):

bash

运行



# Windows命令行SCP复制
scp -r ./publish/linux/* yourname@linux-ip:/home/yourname/yourapp

赋予执行权限:

bash

运行



# Linux端执行
cd /home/yourname/yourapp
chmod +x YourAppName # 赋予可执行权限

运行程序:

bash

运行



# 自包含部署(直接运行可执行文件)
./YourAppName
 
# 框架依赖部署(通过dotnet运行)
dotnet YourAppName.dll
3. 进阶:容器化部署(推荐)

用 Docker 打包程序,避免 Linux 环境依赖问题:

创建
Dockerfile
(项目根目录):

dockerfile



# 基础镜像:.NET 8运行时
FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS base
WORKDIR /app
 
# 构建阶段:编译程序
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src
COPY ["YourApp.csproj", "./"]
RUN dotnet restore "./YourApp.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "YourApp.csproj" -c Release -o /app/build
 
# 发布阶段
FROM build AS publish
RUN dotnet publish "YourApp.csproj" -c Release -o /app/publish /p:UseAppHost=true
 
# 最终镜像
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["./YourApp"]

构建并运行 Docker 镜像:

bash

运行



# Linux端构建镜像
docker build -t yourapp:1.0 .
# 运行容器
docker run --rm --privileged yourapp:1.0 # --privileged:硬件访问需加此参数(串口/USB)

五、步骤 4:调试与问题排查

1. 远程调试(VS 2022)

配置 Linux 远程连接:VS 2022 → 工具 → 选项 → 跨平台 → 连接管理器 → 添加 Linux 主机(IP、用户名、密码);调试设置:项目属性 → 调试 → 目标运行时 → 选择 Linux 主机;打断点后直接运行调试,VS 会自动同步代码到 Linux 并调试(支持变量查看、调用栈等)。

2. 日志排查

添加跨平台日志库(如 Serilog、NLog),输出详细日志到文件,排查 Linux 下的运行问题:

csharp

运行



// 安装Serilog NuGet包:Serilog、Serilog.Sinks.File
using Serilog;
 
// 初始化日志(跨平台)
Log.Logger = new LoggerConfiguration()
    .WriteTo.File("/home/yourname/logs/app.log", rollingInterval: RollingInterval.Day)
    .CreateLogger();
 
// 记录日志
Log.Information("Program started on {OS}", Environment.OSVersion.Platform);
try
{
    // 业务逻辑
}
catch (Exception ex)
{
    Log.Error(ex, "Error occurred");
}
3. 常见问题与解决
问题现象 原因与解决方案
串口 / USB 访问失败 Linux 权限不足:将用户加入
dialout
组(
sudo usermod -aG dialout yourname
),或
sudo ./YourAppName
运行
程序运行报 “找不到库” 自包含部署缺失依赖:用
ldd YourAppName
查看缺失的 SO 库,安装对应包(如
apt install libicu-dev
编码乱码 Linux 默认 UTF-8,Windows 默认 GBK:统一用
Encoding.UTF8
处理文本
UI 程序无法运行 WinForms/WPF 不支持 Linux:替换为 Avalonia 等跨平台 UI 框架

六、示例:完整的跨平台 C# 硬件访问程序

以下是适配 Windows/Linux 的串口访问程序(.NET 8):

1. 项目文件(YourApp.csproj)

xml



<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
 
  <ItemGroup>
    <!-- 跨平台串口库(可选,替代内置System.IO.Ports) -->
    <PackageReference Include="SerialPortStream" Version="3.1.0" />
  </ItemGroup>
</Project>
2. 代码(Program.cs)

csharp

运行



using System.IO.Ports;
using Serilog;
 
// 初始化日志
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.File(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "serial.log"), rollingInterval: RollingInterval.Day)
    .CreateLogger();
 
try
{
    Log.Information("Starting serial port tool on {OS}", Environment.OSVersion.Platform);
 
    // 枚举串口
    string[] ports = SerialPort.GetPortNames();
    if (ports.Length == 0)
    {
        Log.Warning("No serial ports found");
        return;
    }
 
    Log.Information("Found {Count} serial ports:", ports.Length);
    foreach (var port in ports)
    {
        Log.Information("- {Port}", port);
    }
 
    // 打开第一个串口
    using var serialPort = new SerialPort(ports[0], 9600)
    {
        Parity = Parity.None,
        DataBits = 8,
        StopBits = StopBits.One,
        ReadTimeout = 5000
    };
 
    serialPort.Open();
    Log.Information("Opened port {Port}", ports[0]);
 
    // 发送数据
    serialPort.Write("Hello from C# on Linux!");
    Log.Information("Sent data to port");
 
    // 读取数据
    string response = serialPort.ReadLine();
    Log.Information("Received data: {Data}", response);
 
    serialPort.Close();
}
catch (Exception ex)
{
    Log.Error(ex, "Program failed");
}
finally
{
    Log.CloseAndFlush();
}

总结

C# 程序移植到 Linux 的核心流程是:升级到.NET 6+ → 适配平台特定代码 → 跨平台编译 → 部署 / 调试。重点解决 Windows 专属 API、路径、权限、硬件访问的适配问题,优先使用跨平台 NuGet 库和 API,避免硬编码平台逻辑。对于硬件访问场景,.NET 5 + 已内置大部分跨平台硬件操作 API,结合 Docker 部署可大幅降低环境适配成本。

© 版权声明

相关文章

暂无评论

none
暂无评论...