C#跨平台开发


引言

随着.NET Core的推出和后续.NET 5/6/7的演进,C#已从Windows生态语言转变为真正的跨平台开发语言。如今,开发者可以使用C#构建运行在Windows、Linux、macOS、iOS、Android甚至嵌入式设备上的应用程序。本文将全面介绍C#跨平台开发的技术栈、工具链和最佳实践。

1. 跨平台技术栈概览

1.1 .NET统一平台

  • .NET 5/6/7+:微软统一的开发平台
  • 支持的操作系统:
  • Windows (7/8/10/11, Windows Server)
  • Linux (Ubuntu, Debian, RHEL, Alpine等)
  • macOS (10.13+)

1.2 主要跨平台框架

框架适用场景目标平台
.NET MAUI跨平台UIWindows/macOS/iOS/Android
Avalonia跨平台UIWindows/Linux/macOS
Uno Platform跨平台UIWeb/Wasm/iOS/Android/macOS
BlazorWeb/桌面浏览器/桌面应用
ASP.NET CoreWeb应用全平台服务器

2. 跨平台UI开发

2.1 .NET MAUI (多平台应用UI)

项目创建

dotnet new maui -n MyMauiApp

示例代码

// 跨平台页面
public class MainPage : ContentPage
{
    public MainPage()
    {
        Content = new VerticalStackLayout
        {
            Children = {
                new Label { 
                    Text = "Welcome to .NET MAUI!",
                    FontSize = 22,
                    HorizontalOptions = LayoutOptions.Center
                },
                new Button {
                    Text = "Click Me",
                    Command = new Command(() => DisplayAlert("Hello", "You clicked me!", "OK"))
                }
            }
        };
    }
}

平台特定代码

// 共享接口
public interface IDeviceService
{
    string GetPlatformName();
}

// Android实现
#if ANDROID
public class DeviceService : IDeviceService
{
    public string GetPlatformName() => "Android";
}
#endif

// iOS实现
#if IOS
public class DeviceService : IDeviceService
{
    public string GetPlatformName() => "iOS";
}
#endif

2.2 Avalonia UI

项目创建

dotnet new avalonia.app -n MyAvaloniaApp

示例代码

public class MainWindow : Window
{
    public MainWindow()
    {
        Title = "Avalonia跨平台应用";
        Content = new StackPanel
        {
            Children =
            {
                new TextBlock { Text = "Hello World!", FontSize = 20 },
                new Button { Content = "Click Me" }
                    .OnClick((s, e) => MessageBox.Show(this, "Button clicked!"))
            }
        };
    }
}

3. 跨平台服务开发

3.1 Worker Service

创建项目

dotnet new worker -n MyCrossPlatformService

配置为系统服务

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseWindowsService()  // Windows服务
        .UseSystemd()        // Linux systemd服务
        .ConfigureServices(services =>
        {
            services.AddHostedService<Worker>();
        });

3.2 文件系统操作

using System.IO;

// 跨平台路径组合
var configPath = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "MyApp",
    "config.json");

// 跨平台目录分隔符
Console.WriteLine($"分隔符: {Path.DirectorySeparatorChar}");

// 检查操作系统
if (OperatingSystem.IsWindows())
{
    // Windows特定代码
}
else if (OperatingSystem.IsLinux())
{
    // Linux特定代码
}

4. 平台互操作

4.1 条件编译

// 平台检测
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    WindowsSpecificMethod();
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    LinuxSpecificMethod();
}

// 条件编译
#if WINDOWS
    [DllImport("user32.dll")]
    public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
#elif LINUX
    // Linux原生互操作
#endif

4.2 使用Native库

P/Invoke示例

using System.Runtime.InteropServices;

public class NativeMethods
{
    // Windows
    [DllImport("kernel32.dll")]
    public static extern uint GetCurrentThreadId();

    // Linux (需要指定不同库名)
    [DllImport("libc", EntryPoint = "getpid")]
    public static extern int GetProcessId();
}

// 使用
var threadId = NativeMethods.GetCurrentThreadId();

5. 容器化与跨平台部署

5.1 Docker支持

示例Dockerfile

# 多阶段构建
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

# 运行时镜像
FROM mcr.microsoft.com/dotnet/runtime:6.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.dll"]

多平台构建

# 构建Linux容器
docker build -t myapp -f Dockerfile.linux .

# 构建Windows容器
docker build -t myapp -f Dockerfile.windows .

5.2 发布单文件应用

# 发布自包含单文件应用
dotnet publish -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true

6. 跨平台开发工具

6.1 Visual Studio Code

推荐扩展

  • C# (ms-dotnettools.csharp)
  • .NET MAUI (ms-dotnettools.dotnet-maui)
  • Docker (ms-azuretools.vscode-docker)
  • Remote – Containers (ms-vscode-remote.remote-containers)

6.2 调试配置

.vscode/launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch",
            "type": "coreclr",
            "request": "launch",
            "program": "${workspaceFolder}/bin/Debug/net6.0/MyApp.dll",
            "args": [],
            "cwd": "${workspaceFolder}",
            "console": "internalConsole"
        }
    ]
}

7. 最佳实践

7.1 文件路径处理

// 避免硬编码路径分隔符
var badPath = "folder\\file";  // ❌ Windows特定
var goodPath = Path.Combine("folder", "file");  // ✅ 跨平台

// 使用Path类处理所有路径操作
var fullPath = Path.GetFullPath("./config");
var dirName = Path.GetDirectoryName(fullPath);

7.2 行尾符处理

// 使用Environment.NewLine替代\n或\r\n
var text = $"Line1{Environment.NewLine}Line2";

// 读取文件时统一处理
var content = File.ReadAllText("file.txt")
    .Replace("\r\n", "\n")  // Windows换行→Unix
    .Replace("\r", "\n");   // 旧Mac换行→Unix

7.3 文化敏感处理

// 明确指定文化信息
var number = 1234.56;
var invariant = number.ToString(CultureInfo.InvariantCulture); // "1234.56"
var local = number.ToString(CultureInfo.CurrentCulture);       // 可能"1234,56"

// 解析时指定文化
var parsed = double.Parse("1234.56", CultureInfo.InvariantCulture);

8. 实际案例

8.1 跨平台配置文件加载

public static string GetConfigPath()
{
    var basePath = Environment.GetFolderPath(
        Environment.SpecialFolder.ApplicationData);

    if (OperatingSystem.IsLinux())
    {
        basePath = Environment.GetFolderPath(
            Environment.SpecialFolder.UserProfile);
    }

    return Path.Combine(basePath, ".myapp", "config.json");
}

8.2 跨平台进程管理

public static void OpenBrowser(string url)
{
    try
    {
        if (OperatingSystem.IsWindows())
        {
            Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
        }
        else if (OperatingSystem.IsLinux())
        {
            Process.Start("xdg-open", url);
        }
        else if (OperatingSystem.IsMacOS())
        {
            Process.Start("open", url);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"无法打开浏览器: {ex.Message}");
    }
}

结语

C#跨平台开发已经成熟,通过.NET统一平台和丰富的框架选择,开发者可以构建真正原生的跨平台应用。关键要点包括:

  1. 选择合适的UI框架:根据目标平台选择.NET MAUI、Avalonia或Blazor
  2. 抽象平台差异:通过条件编译和运行时检测处理平台特定代码
  3. 遵循跨平台最佳实践:正确处理路径、行尾符和文化差异
  4. 利用现代化工具链:使用容器化、单文件发布等简化部署

随着.NET生态的持续发展,C#已成为跨平台开发的强大选择,既保持了企业级语言的严谨性,又具备了现代开发所需的灵活性。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注