本文将继续补充 .NET Core(现为 .NET,如 .NET 5/6/7/8)在上位机开发中常用的方法和编程方式,延续之前的详细说明,重点针对大数据量、硬件交互和高实时性需求场景。以下内容将进一步扩展,增加更多实用方法,涵盖文件操作、序列化、事件驱动、跨平台支持、测试与调试等,确保覆盖上位机开发的广泛需求。每种方法提供详细说明、示例代码、上位机适用场景、注意事项,并与 .NET Framework 对比。


十六、文件操作与存储

  1. System.IO Asynchronous File Operations

    • 功能:提供异步文件读写方法(如 File.ReadAllBytesAsync, File.WriteAllTextAsync),优化 I/O 性能。

    • 上位机场景:存储传感器数据到文件(如日志或历史数据),适合高吞吐量场景。

    • 示例:异步写入传感器数据到 CSV 文件:

      csharp

      public async Task SaveDataToFileAsync(SensorData data, string filePath)
      {
          string csvLine = $"{data.Id},{data.Value},{data.Timestamp:O}";
          await File.AppendAllTextAsync(filePath, csvLine + Environment.NewLine);
      }
      
      public async Task ReadDataFromFileAsync(string filePath)
      {
          string content = await File.ReadAllTextAsync(filePath);
          // 解析 CSV
          foreach (var line in content.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries))
          {
              var parts = line.Split(',');
              var data = new SensorData(int.Parse(parts[0]), double.Parse(parts[1]), DateTime.Parse(parts[2]));
              Console.WriteLine($"Read: {data}");
          }
      }
    • 注意事项:

      • 使用异步方法避免阻塞,特别是在 UI 线程。

      • 确保文件路径权限,特别是在嵌入式设备上。

      • 对于大数据量,考虑分块写入:

        csharp

        using var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true);
        await stream.WriteAsync(dataBuffer);
    • 优势:异步 I/O 减少阻塞,适合高实时性场景(<50ms 延迟)。

    • 对比 .NET Framework:Framework 提供同步方法(如 File.WriteAllText),异步支持需手动实现,性能较低。

  2. System.IO.Stream with Asynchronous Buffering

    • 功能:结合 Stream 的异步方法(如 ReadAsync, WriteAsync)和缓冲区管理,优化文件或网络流处理。

    • 上位机场景:处理大文件(如 GB 级数据备份)或实时流(如硬件数据流)。

    • 示例:异步写入大数据到文件:

      csharp

      public async Task WriteLargeDataAsync(byte[] data, string filePath)
      {
          using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 8192, useAsync: true);
          await stream.WriteAsync(data.AsMemory());
      }
    • 注意事项:

      • 配置合适的缓冲区大小(bufferSize),通常为 4KB 或 8KB。

      • 使用 ArrayPool 管理缓冲区,减少内存分配:

        csharp

        byte[] buffer = ArrayPool<byte>.Shared.Rent(8192);
        try
        {
            int bytesRead = await sourceStream.ReadAsync(buffer);
            await targetStream.WriteAsync(buffer.AsMemory(0, bytesRead));
        }
        finally
        {
            ArrayPool<byte>.Shared.Return(buffer);
        }
    • 优势:高效处理大文件或流,适合 GB 级数据存储。

    • 对比 .NET Framework:Framework 的 Stream 支持异步,但 .NET Core 性能更高,API 更现代化。


十七、事件驱动与消息处理

  1. System.Reactive (Rx.NET)

    • 功能:提供反应式编程模型,处理异步事件流,支持复杂事件处理(如过滤、聚合)。

    • 上位机场景:实时监控传感器数据,触发事件(如阈值报警)。

    • 示例:监控传感器数据并触发报警:

      csharp

      using System.Reactive.Linq;
      
      public IObservable<SensorData> ObserveSensorDataAsync()
      {
          return Observable.Create<SensorData>(async observer =>
          {
              using var cts = new CancellationTokenSource();
              while (!cts.Token.IsCancellationRequested)
              {
                  byte[] rawData = await ReadFromHardwareAsync();
                  var data = new SensorData(rawData[0], BitConverter.ToDouble(rawData, 1), DateTime.Now);
                  observer.OnNext(data);
                  await Task.Delay(50, cts.Token);
              }
          });
      }
      
      public void MonitorData()
      {
          ObserveSensorDataAsync()
              .Where(data => data.Value > 100.0) // 过滤高值
              .Subscribe(data => Console.WriteLine($"Alarm: High value {data.Value} at {data.Timestamp}"));
      }
    • 注意事项:

      • 使用 SubscribeOn 和 ObserveOn 控制线程:

        csharp

        .SubscribeOn(TaskPoolScheduler.Default)
        .ObserveOn(DispatcherScheduler.Current)
      • 管理订阅生命周期,调用 Dispose 避免泄漏。

    • 优势:声明式事件处理,适合实时监控和复杂逻辑。

    • 对比 .NET Framework:Framework 支持 Rx.NET,但 .NET Core 集成更紧密,性能更高。

  2. EventHandler with Async Support

    • 功能:支持异步事件处理,结合 async/await 实现非阻塞事件响应。

    • 上位机场景:处理硬件数据到达事件(如串口数据接收)。

    • 示例:

      csharp

      public class HardwareManager
      {
          public event Func<SensorData, Task> DataReceived;
      
          public async Task StartAsync(CancellationToken ct)
          {
              while (!ct.IsCancellationRequested)
              {
                  byte[] rawData = await ReadFromHardwareAsync();
                  var data = new SensorData(rawData[0], BitConverter.ToDouble(rawData, 1), DateTime.Now);
                  if (DataReceived != null)
                  {
                      await DataReceived.Invoke(data);
                  }
              }
          }
      }
      
      public class DataProcessor
      {
          public DataProcessor(HardwareManager manager)
          {
              manager.DataReceived += async (data) =>
              {
                  await ProcessDataAsync(data);
              };
          }
      
          private async Task ProcessDataAsync(SensorData data)
          {
              await Task.Delay(10); // 模拟处理
              Console.WriteLine($"Processed: {data}");
          }
      }
    • 注意事项:

      • 使用 async void 仅限于事件处理程序。

      • 确保事件处理程序异常不会中断主流程:

        csharp

        try { await DataReceived.Invoke(data); } catch { /* 记录错误 */ }
    • 优势:异步事件处理,适合高实时性场景。

    • 对比 .NET Framework:Framework 的事件处理通常同步,异步支持需手动实现。


十八、跨平台与嵌入式支持

  1. System.Device.Gpio

    • 功能:提供 GPIO 操作,适用于嵌入式设备(如 Raspberry Pi)。

    • 上位机场景:控制工业设备 GPIO 引脚(如开关继电器)。

    • 示例:

      csharp

      using System.Device.Gpio;
      
      public class GpioControllerService
      {
          private readonly GpioController _controller;
      
          public GpioControllerService()
          {
              _controller = new GpioController();
          }
      
          public void TogglePin(int pinNumber, bool state)
          {
              _controller.OpenPin(pinNumber, PinMode.Output);
              _controller.Write(pinNumber, state ? PinValue.High : PinValue.Low);
          }
      }
    • 注意事项:

      • 确保设备支持 GPIO(如 Raspberry Pi)。

      • 检查权限,特别是在 Linux 系统上。

    • 优势:跨平台支持,适合嵌入式上位机。

    • 对比 .NET Framework:Framework 无内置 GPIO 支持,需第三方库。

  2. System.Runtime.InteropServices for Cross-Platform P/Invoke

    • 功能:优化 P/Invoke 调用,支持跨平台调用本地库(如 Linux 的 libserialport)。

    • 上位机场景:访问低级硬件接口(如自定义串口驱动)。

    • 示例:

      csharp

      using System.Runtime.InteropServices;
      
      public class NativeSerialPort
      {
          [DllImport("libserialport.so", EntryPoint = "sp_get_port_by_name")]
          private static extern IntPtr GetPortByName(string portName);
      
          public void OpenPort(string portName)
          {
              IntPtr port = GetPortByName(portName);
              // 继续本地调用
              Console.WriteLine($"Opened port: {portName}");
          }
      }
    • 注意事项:

      • 使用 [DllImport] 指定平台特定的库名称。

      • 提供 Windows 和 Linux 的实现路径:

        csharp

        private const string LibName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "kernel32.dll" : "libserialport.so";
    • 优势:支持跨平台硬件交互,适合 Linux 工控机。

    • 对比 .NET Framework:Framework 的 P/Invoke 仅限 Windows,跨平台支持差。


十九、测试与调试

  1. xUnit with Async Testing

    • 功能:支持异步单元测试,验证上位机逻辑。

    • 上位机场景:测试数据处理或硬件交互逻辑。

    • 示例:

      csharp

      using Xunit;
      
      public class DataProcessorTests
      {
          [Fact]
          public async Task ProcessDataAsync_ValidData_Succeeds()
          {
              var processor = new DataProcessor();
              var data = new SensorData(1, 100.0, DateTime.Now);
              await processor.ProcessDataAsync(data);
              Assert.True(true); // 验证逻辑
          }
      }
    • 注意事项:

      • 使用 async Task 而非 async void。

      • 模拟硬件交互以避免测试依赖:

        csharp

        public class MockHardwareManager : IHardwareManager
        {
            public async ValueTask<byte[]> ReadAsync(CancellationToken ct)
            {
                return new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }; // 模拟数据
            }
        }
    • 优势:异步测试支持,适合验证高并发逻辑。

    • 对比 .NET Framework:Framework 的测试框架(如 MSTest)异步支持较弱。

  2. BenchmarkDotNet

    • 功能:高性能基准测试工具,分析方法性能。

    • 上位机场景:优化数据解析或硬件交互性能。

    • 示例:

      csharp

      using BenchmarkDotNet.Attributes;
      using BenchmarkDotNet.Running;
      
      [MemoryDiagnoser]
      public class DataParserBenchmarks
      {
          private readonly byte[] _data = new byte[1024];
      
          [Benchmark]
          public int ParseWithSpan()
          {
              return BitConverter.ToInt32(_data.AsSpan());
          }
      
          [Benchmark]
          public int ParseWithArray()
          {
              return BitConverter.ToInt32(_data);
          }
      }
      
      public static void Main()
      {
          BenchmarkRunner.Run<DataParserBenchmarks>();
      }
    • 注意事项:

      • 运行在 Release 模式,确保准确结果。

      • 分析内存分配和执行时间,优化关键路径。

    • 优势:精确测量性能,适合优化实时性(如 <10ms 延迟)。

    • 对比 .NET Framework:Framework 支持 BenchmarkDotNet,但 .NET Core 性能分析更精准。


二十、综合示例:增强版上位机应用

以下是一个更复杂的综合示例,整合更多方法,展示实时采集、处理、存储、通信和监控:

csharp

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Device.Gpio;
using System.IO.Pipelines;
using System.Reactive.Linq;
using System.Text.Json;
using System.Threading.Channels;

public record SensorData(int Id, double Value, DateTime Timestamp);

public interface IHardwareManager
{
    ValueTask<byte[]> ReadAsync(CancellationToken ct);
    void TogglePin(int pinNumber, bool state);
}

public class HardwareManager : IHardwareManager
{
    private readonly GpioController _gpio;
    private readonly ILogger<HardwareManager> _logger;
    private readonly PipeReader _pipeReader;

    public HardwareManager(IConfiguration config, ILogger<HardwareManager> logger)
    {
        _gpio = new GpioController();
        _logger = logger;
        _pipeReader = CreatePipeReader(); // 模拟硬件数据流
    }

    public async ValueTask<byte[]> ReadAsync(CancellationToken ct)
    {
        var result = await _pipeReader.ReadAsync(ct);
        var buffer = result.Buffer;
        try
        {
            if (buffer.Length >= 8)
            {
                var slice = buffer.Slice(0, 8);
                _logger.LogInformation("Read {Length} bytes", slice.Length);
                return slice.ToArray();
            }
            return Array.Empty<byte>();
        }
        finally
        {
            _pipeReader.AdvanceTo(buffer.Start, buffer.End);
        }
    }

    public void TogglePin(int pinNumber, bool state)
    {
        _gpio.OpenPin(pinNumber, PinMode.Output);
        _gpio.Write(pinNumber, state ? PinValue.High : PinValue.Low);
    }

    private PipeReader CreatePipeReader()
    {
        var pipe = new Pipe();
        Task.Run(async () =>
        {
            while (true)
            {
                await pipe.Writer.WriteAsync(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 });
                await Task.Delay(50);
            }
        });
        return pipe.Reader;
    }
}

public class DataProcessor
{
    private readonly Channel<SensorData> _dataChannel = Channel.CreateBounded<SensorData>(10000);
    private readonly IHardwareManager _hardware;
    private readonly ILogger<DataProcessor> _logger;
    private readonly IObservable<SensorData> _dataObservable;

    public DataProcessor(IHardwareManager hardware, ILogger<DataProcessor> logger)
    {
        _hardware = hardware;
        _logger = logger;
        _dataObservable = Observable.Create<SensorData>(async observer =>
        {
            while (true)
            {
                byte[] rawData = await _hardware.ReadAsync(CancellationToken.None);
                var data = new SensorData(rawData[0], BitConverter.ToDouble(rawData, 1), DateTime.Now);
                observer.OnNext(data);
            }
        });
    }

    public async Task StartAcquisitionAsync(CancellationToken ct)
    {
        using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(50));
        while (await timer.WaitForNextTickAsync(ct))
        {
            byte[] rawData = await _hardware.ReadAsync(ct);
            var data = new SensorData(rawData[0], BitConverter.ToDouble(rawData, 1), DateTime.Now);
            await _dataChannel.Writer.WriteAsync(data, ct);
            _hardware.TogglePin(18, data.Value > 100); // 控制 GPIO
        }
    }

    public void MonitorHighValues()
    {
        _dataObservable
            .Where(data => data.Value > 100)
            .Subscribe(data => _logger.LogWarning("High value detected: {Value}", data.Value));
    }

    public async Task SaveToFileAsync(CancellationToken ct)
    {
        await foreach (var data in _dataChannel.Reader.ReadAllAsync(ct))
        {
            string json = JsonSerializer.Serialize(data);
            await File.AppendAllTextAsync("data.json", json + Environment.NewLine, ct);
        }
    }
}

public class Program
{
    public static async Task Main()
    {
        var services = new ServiceCollection();
        services.AddLogging(builder => builder.AddConsole());
        services.AddSingleton<IConfiguration>(new ConfigurationBuilder().AddJsonFile("appsettings.json").Build());
        services.AddSingleton<IHardwareManager, HardwareManager>();
        services.AddSingleton<DataProcessor>();
        var provider = services.BuildServiceProvider();

        var processor = provider.GetService<DataProcessor>();
        using var cts = new CancellationTokenSource();

        processor.MonitorHighValues();
        var acquisitionTask = processor.StartAcquisitionAsync(cts.Token);
        var saveTask = processor.SaveToFileAsync(cts.Token);

        Console.ReadLine();
        cts.Cancel();
        await Task.WhenAll(acquisitionTask, saveTask);
    }
}

示例说明:

  • 硬件交互:HardwareManager 使用 System.IO.Pipelines 和 System.Device.Gpio 模拟硬件数据流和 GPIO 控制。

  • 数据处理:DataProcessor 使用 Channel, PeriodicTimer, System.Reactive 实现实时采集和监控。

  • 存储:异步写入 JSON 文件(System.Text.Json 和 File.AppendAllTextAsync)。

  • 现代化特性:DI, Logging, record, 提高代码可维护性。


二十一、总结

新增方法汇总:

  • 文件操作:File.ReadAllBytesAsync, File.WriteAllTextAsync, Stream 异步方法。

  • 事件驱动:System.Reactive, Async EventHandler.

  • 跨平台:System.Device.Gpio, System.Runtime.InteropServices.

  • 测试与调试:xUnit 异步测试, BenchmarkDotNet.

  • 综合:整合 Configuration, Logging, DI, Pipelines, Reactive 等。

上位机优势:

  • 大数据量:Pipelines, File 异步方法处理 GB 级数据流,内存效率高。

  • 硬件交互:GPIO, P/Invoke 支持嵌入式设备,异步方法降低延迟。

  • 高实时性:PeriodicTimer, Reactive 实现 <50ms 实时监控。

  • 跨平台:支持 Linux 工控机,适合混合部署。

  • 调试与维护:xUnit, BenchmarkDotNet 优化性能和可靠性。

对比 .NET Framework:

  • .NET Core 提供更高性能(延迟低 20%-50%)、跨平台支持、现代化 API。

  • Framework 缺乏 Pipelines, GPIO, System.Text.Json, 异步文件操作等,开发效率和性能较差。

若需针对特定场景(如特定硬件协议、数据量、实时性要求)提供更详细代码或优化,请提供更多细节!

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐