C#高级编程中几个核心知识点的更详细代码示例,结合上位机开发场景,涵盖反射、接口与抽象类、泛型、委托与事件、多线程与异步编程、设计模式(单例与工厂)以及一个完整的上位机温度监控系统实战示例,李工详解

以下为C#高级编程中几个核心知识点的更详细代码示例,结合上位机开发场景,涵盖反射、接口与抽象类、泛型、委托与事件、多线程与异步编程、设计模式(单例与工厂)以及一个完整的上位机温度监控系统实战示例。每个示例都包含详细注释、异常处理和上位机开发中的实际应用场景,旨在帮助您深入理解并快速应用到实际项目中。


1. 反射(Reflection)

详细代码示例

csharp

using System;
using System.Reflection;

// 设备配置类
public class DeviceConfig
{
    public string Name { get; set; }
    public int Id { get; set; }
    public bool IsActive { get; set; }

    public void Start() => Console.WriteLine($"{Name} 启动");
}

// 反射管理器
public class DeviceReflectionManager
{
    // 动态创建对象
    public static object CreateInstance(string typeName)
    {
        try
        {
            Type type = Type.GetType(typeName) ?? throw new ArgumentException($"类型 {typeName} 未找到");
            return Activator.CreateInstance(type);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"创建实例失败: {ex.Message}");
            return null;
        }
    }

    // 动态设置属性
    public static void SetProperty(object instance, string propertyName, object value)
    {
        try
        {
            PropertyInfo prop = instance.GetType().GetProperty(propertyName) 
                ?? throw new ArgumentException($"属性 {propertyName} 未找到");
            prop.SetValue(instance, value);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"设置属性失败: {ex.Message}");
        }
    }

    // 动态调用方法
    public static void InvokeMethod(object instance, string methodName)
    {
        try
        {
            MethodInfo method = instance.GetType().GetMethod(methodName) 
                ?? throw new ArgumentException($"方法 {methodName} 未找到");
            method.Invoke(instance, null);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"调用方法失败: {ex.Message}");
        }
    }
}

class Program
{
    static void Main()
    {
        // 动态创建 DeviceConfig 实例
        object device = DeviceReflectionManager.CreateInstance("DeviceConfig");
        if (device == null) return;

        // 动态设置属性
        DeviceReflectionManager.SetProperty(device, "Name", "Sensor1");
        DeviceReflectionManager.SetProperty(device, "Id", 101);
        DeviceReflectionManager.SetProperty(device, "IsActive", true);

        // 验证属性
        DeviceConfig config = (DeviceConfig)device;
        Console.WriteLine($"设备: {config.Name}, ID: {config.Id}, 状态: {config.IsActive}");

        // 动态调用方法
        DeviceReflectionManager.InvokeMethod(device, "Start");
    }
}

上位机应用

  • 场景:上位机需要动态加载设备驱动(如从DLL或配置文件中读取类型名)。

  • 实现:通过反射创建设备实例,设置配置(如设备地址、通信协议),并调用其方法(如Start、Stop)。

  • 优点:支持插件化开发,扩展性强。

  • 注意:反射性能开销较大,建议缓存Type和PropertyInfo对象。


2. 接口与抽象类

详细代码示例

csharp

using System;

// 定义通信接口
public interface ICommunication
{
    void Connect();
    void Disconnect();
    string ReadData();
}

// 抽象基类,包含通用逻辑
public abstract class BaseDevice
{
    protected string DeviceName { get; set; }
    protected bool IsConnected { get; private set; }

    public void Log(string message) => Console.WriteLine($"[{DeviceName}] {message}");

    public void SetConnectionStatus(bool status)
    {
        IsConnected = status;
        Log($"连接状态: {(status ? "已连接" : "已断开")}");
    }
}

// 串口通信实现
public class SerialDevice : BaseDevice, ICommunication
{
    public SerialDevice(string name) => DeviceName = name;

    public void Connect()
    {
        SetConnectionStatus(true);
        Log("串口连接成功");
    }

    public void Disconnect()
    {
        SetConnectionStatus(false);
        Log("串口断开");
    }

    public string ReadData()
    {
        if (!IsConnected) throw new InvalidOperationException("设备未连接");
        return "温度: 25.5°C";
    }
}

// TCP通信实现
public class TcpDevice : BaseDevice, ICommunication
{
    public TcpDevice(string name) => DeviceName = name;

    public void Connect()
    {
        SetConnectionStatus(true);
        Log("TCP连接成功");
    }

    public void Disconnect()
    {
        SetConnectionStatus(false);
        Log("TCP断开");
    }

    public string ReadData()
    {
        if (!IsConnected) throw new InvalidOperationException("设备未连接");
        return "压力: 1.2bar";
    }
}

class Program
{
    static void Main()
    {
        ICommunication serial = new SerialDevice("传感器1");
        ICommunication tcp = new TcpDevice("传感器2");

        // 统一调用接口方法
        serial.Connect();
        Console.WriteLine(serial.ReadData());
        serial.Disconnect();

        tcp.Connect();
        Console.WriteLine(tcp.ReadData());
        tcp.Disconnect();
    }
}

上位机应用

  • 场景:上位机需要支持多种通信协议(如串口、TCP、Modbus)。

  • 实现:定义ICommunication接口,抽象出通用方法;使用抽象类BaseDevice共享日志和状态管理逻辑。

  • 优点:代码解耦,易于扩展新协议。

  • 注意:确保接口方法设计合理,避免过于复杂的契约。


3. 泛型

详细代码示例

csharp

using System;
using System.Collections.Generic;

// 泛型数据缓冲区,支持约束
public class DataBuffer where T : struct
{
    private readonly List _buffer;
    private readonly int _maxSize;

    public DataBuffer(int maxSize = 100)
    {
        _maxSize = maxSize;
        _buffer = new List(maxSize);
    }

    public void Add(T item)
    {
        if (_buffer.Count >= _maxSize)
        {
            _buffer.RemoveAt(0); // 移除最早的数据
        }
        _buffer.Add(item);
    }

    public T Get(int index)
    {
        if (index < 0 || index >= _buffer.Count)
            throw new ArgumentOutOfRangeException(nameof(index));
        return _buffer[index];
    }

    public int Count => _buffer.Count;

    public void Clear() => _buffer.Clear();
}

// 数据处理器
public class DataProcessor
{
    public static double CalculateAverage(DataBuffer buffer) where T : struct
    {
        if (buffer.Count == 0) return 0;

        double sum = 0;
        for (int i = 0; i < buffer.Count; i++)
        {
            sum += Convert.ToDouble(buffer.Get(i));
        }
        return sum / buffer.Count;
    }
}

class Program
{
    static void Main()
    {
        DataBuffer tempBuffer = new DataBuffer(3);
        tempBuffer.Add(25.5);
        tempBuffer.Add(26.0);
        tempBuffer.Add(25.8);

        Console.WriteLine($"缓冲区数据量: {tempBuffer.Count}");
        Console.WriteLine($"平均温度: {DataProcessor.CalculateAverage(tempBuffer):F2}°C");

        // 添加超过最大容量的数据
        tempBuffer.Add(27.0);
        Console.WriteLine($"最新数据: {tempBuffer.Get(tempBuffer.Count - 1)}");
    }
}

上位机应用

  • 场景:上位机需要缓存不同类型的数据(如温度double、压力float)。

  • 实现:使用泛型DataBuffer存储数据,支持固定大小的滑动窗口;DataProcessor提供通用计算逻辑。

  • 优点:类型安全,代码复用性高。

  • 注意:泛型约束(如where T : struct)确保数据类型符合需求。


4. 委托与事件

详细代码示例

csharp

using System;
using System.Threading;

// 数据接收处理器委托
public delegate void DataReceivedHandler(T data, DateTime timestamp);

// 数据采集器
public class DataCollector
{
    public event DataReceivedHandler OnDataReceived;

    public void StartCollecting()
    {
        try
        {
            while (true)
            {
                // 模拟采集数据
                double data = new Random().NextDouble() * 100;
                OnDataReceived?.Invoke(data, DateTime.Now);
                Thread.Sleep(1000); // 每秒采集一次
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"采集错误: {ex.Message}");
        }
    }
}

// 数据处理器
public class DataProcessor
{
    public void Subscribe(DataCollector collector)
    {
        // 使用Lambda表达式订阅事件
        collector.OnDataReceived += (data, timestamp) =>
        {
            Console.WriteLine($"[{timestamp:HH:mm:ss}] 收到数据: {data:F2}");
            if (data > 80)
                Console.WriteLine("警告: 数据超出阈值!");
        };
    }
}

class Program
{
    static void Main()
    {
        DataCollector collector = new DataCollector();
        DataProcessor processor = new DataProcessor();

        processor.Subscribe(collector);

        // 在新线程中启动采集
        Thread thread = new Thread(collector.StartCollecting);
        thread.Start();

        Console.ReadLine(); // 保持程序运行
    }
}

上位机应用

  • 场景:上位机需要实时处理传感器数据并触发报警。

  • 实现:使用事件通知数据到达,处理器根据数据值执行逻辑(如报警、记录)。

  • 优点:解耦采集与处理逻辑,支持多个订阅者。

  • 注意:确保事件触发时线程安全,避免UI线程阻塞。


5. 多线程与异步编程

详细代码示例

csharp

using System;
using System.IO.Ports;
using System.Threading.Tasks;

public class SerialDataReader
{
    private readonly SerialPort _port;
    private bool _isRunning;

    public SerialDataReader(string portName, int baudRate)
    {
        _port = new SerialPort(portName, baudRate)
        {
            ReadTimeout = 500
        };
    }

    public event Action OnDataReceived;

    public async Task StartReadingAsync(CancellationToken token)
    {
        try
        {
            _port.Open();
            _isRunning = true;

            while (_isRunning && !token.IsCancellationRequested)
            {
                try
                {
                    // 异步读取串口数据
                    string data = await Task.Run(() => _port.ReadLine(), token);
                    OnDataReceived?.Invoke(data);
                }
                catch (TimeoutException)
                {
                    // 忽略超时,继续读取
                    continue;
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"串口读取错误: {ex.Message}");
        }
        finally
        {
            if (_port.IsOpen) _port.Close();
        }
    }

    public void Stop() => _isRunning = false;
}

class Program
{
    static async Task Main()
    {
        SerialDataReader reader = new SerialDataReader("COM1", 9600);
        CancellationTokenSource cts = new CancellationTokenSource();

        reader.OnDataReceived += data => Console.WriteLine($"收到: {data}");

        // 启动异步读取
        Task readingTask = reader.StartReadingAsync(cts.Token);

        Console.WriteLine("按任意键停止...");
        Console.ReadKey();

        // 停止读取
        cts.Cancel();
        reader.Stop();
        await readingTask;
    }
}

上位机应用

  • 场景:上位机通过串口实时读取传感器数据,保持UI响应性。

  • 实现:使用async/await异步读取串口数据,CancellationToken支持优雅停止。

  • 优点:避免阻塞主线程,支持取消操作。

  • 注意:处理串口异常(如端口被占用、超时),确保资源释放。


6. 设计模式(单例与工厂)

详细代码示例

csharp

using System;
using System.Collections.Generic;

// 通信接口
public interface ICommunication
{
    void SendData(string data);
}

// 串口通信
public class SerialCommunication : ICommunication
{
    public void SendData(string data) => Console.WriteLine($"串口发送: {data}");
}

// TCP通信
public class TcpCommunication : ICommunication
{
    public void SendData(string data) => Console.WriteLine($"TCP发送: {data}");
}

// 单例模式:通信管理器
public class CommunicationManager
{
    private static CommunicationManager _instance;
    private static readonly object _lock = new object();

    private CommunicationManager() { }

    public static CommunicationManager Instance
    {
        get
        {
            lock (_lock)
            {
                return _instance ??= new CommunicationManager();
            }
        }
    }

    private readonly Dictionary _comms = new Dictionary();

    public void Register(string key, ICommunication comm)
    {
        _comms[key] = comm ?? throw new ArgumentNullException(nameof(comm));
    }

    public ICommunication Get(string key)
    {
        return _comms.TryGetValue(key, out var comm) ? comm : throw new KeyNotFoundException($"未找到 {key}");
    }
}

// 工厂模式:通信创建器
public class CommunicationFactory
{
    public static ICommunication CreateCommunication(string type)
    {
        return type.ToLower() switch
        {
            "serial" => new SerialCommunication(),
            "tcp" => new TcpCommunication(),
            _ => throw new ArgumentException($"未知通信类型: {type}")
        };
    }
}

class Program
{
    static void Main()
    {
        // 使用工厂创建通信实例
        ICommunication serial = CommunicationFactory.CreateCommunication("serial");
        ICommunication tcp = CommunicationFactory.CreateCommunication("tcp");

        // 注册到单例管理器
        CommunicationManager manager = CommunicationManager.Instance;
        manager.Register("serial", serial);
        manager.Register("tcp", tcp);

        // 使用通信
        manager.Get("serial").SendData("Hello Serial");
        manager.Get("tcp").SendData("Hello TCP");
    }
}

上位机应用

  • 单例模式:确保上位机中只有一个通信管理器,统一管理所有设备连接。

  • 工厂模式:根据配置文件或用户选择动态创建通信实例(如串口或TCP)。

  • 优点:单例保证全局唯一,工厂增强扩展性。

  • 注意:工厂模式中应避免硬编码,考虑使用配置文件或反射动态加载。


7. 上位机实战:温度监控系统

完整代码示例

以下是一个简化的WPF上位机程序,用于通过串口读取温度数据,实时显示曲线,并支持数据保存到SQLite数据库。

项目结构

  • MainWindow.xaml:WPF界面,显示温度曲线和当前值。

  • TemperatureMonitor.cs:处理串口通信和数据采集。

  • DataBuffer.cs:泛型数据缓冲区。

  • DatabaseHelper.cs:SQLite数据存储。

代码

csharp

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using LiveCharts;
using LiveCharts.Wpf;
using System.Data.SQLite;

// 泛型数据缓冲区
public class DataBuffer where T : struct
{
    private readonly List _buffer = new List();
    private readonly int _maxSize;

    public DataBuffer(int maxSize) => _maxSize = maxSize;

    public void Add(T item)
    {
        if (_buffer.Count >= _maxSize) _buffer.RemoveAt(0);
        _buffer.Add(item);
    }

    public IReadOnlyList GetAll() => _buffer.AsReadOnly();
}

// SQLite数据库帮助类
public class DatabaseHelper
{
    private readonly string _connectionString;

    public DatabaseHelper(string dbPath)
    {
        _connectionString = $"Data Source={dbPath};Version=3;";
        InitializeDatabase();
    }

    private void InitializeDatabase()
    {
        using (var conn = new SQLiteConnection(_connectionString))
        {
            conn.Open();
            string sql = @"CREATE TABLE IF NOT EXISTS Temperature (
                            Id INTEGER PRIMARY KEY AUTOINCREMENT,
                            Value REAL NOT NULL,
                            Timestamp TEXT NOT NULL)";
            using (var cmd = new SQLiteCommand(sql, conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
    }

    public void SaveTemperature(double value, DateTime timestamp)
    {
        using (var conn = new SQLiteConnection(_connectionString))
        {
            conn.Open();
            string sql = "INSERT INTO Temperature (Value, Timestamp) VALUES (@value, @timestamp)";
            using (var cmd = new SQLiteCommand(sql, conn))
            {
                cmd.Parameters.AddWithValue("@value", value);
                cmd.Parameters.AddWithValue("@timestamp", timestamp.ToString("yyyy-MM-dd HH:mm:ss"));
                cmd.ExecuteNonQuery();
            }
        }
    }
}

// 温度监控类
public class TemperatureMonitor
{
    private readonly SerialPort _port;
    private readonly DataBuffer _buffer;
    private readonly DatabaseHelper _db;
    private bool _isRunning;

    public event Action OnTemperatureReceived;

    public TemperatureMonitor(string portName, int baudRate, string dbPath)
    {
        _port = new SerialPort(portName, baudRate) { ReadTimeout = 500 };
        _buffer = new DataBuffer(100);
        _db = new DatabaseHelper(dbPath);
    }

    public async Task StartAsync(CancellationToken token)
    {
        try
        {
            _port.Open();
            _isRunning = true;

            while (_isRunning && !token.IsCancellationRequested)
            {
                try
                {
                    string data = await Task.Run(() => _port.ReadLine(), token);
                    if (double.TryParse(data, out double temp))
                    {
                        _buffer.Add(temp);
                        _db.SaveTemperature(temp, DateTime.Now);
                        OnTemperatureReceived?.Invoke(temp);
                    }
                }
                catch (TimeoutException) { continue; }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"串口错误: {ex.Message}");
        }
        finally
        {
            if (_port.IsOpen) _port.Close();
        }
    }

    public IReadOnlyList GetHistoryData() => _buffer.GetAll();

    public void Stop() => _isRunning = false;
}

// ViewModel(MVVM模式)
public class MainViewModel : INotifyPropertyChanged
{
    private double _currentTemperature;
    public ChartValues TemperatureValues { get; } = new ChartValues();
    public TemperatureMonitor Monitor { get; }

    public double CurrentTemperature
    {
        get => _currentTemperature;
        set
        {
            _currentTemperature = value;
            OnPropertyChanged();
        }
    }

    public MainViewModel()
    {
        Monitor = new TemperatureMonitor("COM1", 9600, "temperature.db");
        Monitor.OnTemperatureReceived += temp =>
        {
            CurrentTemperature = temp;
            TemperatureValues.Add(temp);
            if (TemperatureValues.Count > 100) TemperatureValues.RemoveAt(0);
        };
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

// WPF主窗口(MainWindow.xaml.cs)
public partial class MainWindow : Window
{
    private readonly MainViewModel _viewModel;
    private readonly CancellationTokenSource _cts = new CancellationTokenSource();

    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new MainViewModel();
        DataContext = _viewModel;

        Loaded += async (s, e) => await _viewModel.Monitor.StartAsync(_cts.Token);
        Closing += (s, e) =>
        {
            _cts.Cancel();
            _viewModel.Monitor.Stop();
        };
    }
}

// MainWindow.xaml(部分)
/*

    
        
            
            
                
                    
                
                
                    
                
                
                    
                
            
        
    

*/

说明

  • 功能:

    • 通过串口读取温度数据(模拟为字符串输入)。

    • 实时更新WPF界面中的温度值和曲线(使用LiveCharts)。

    • 将数据保存到SQLite数据库。

  • 技术点:

    • MVVM模式:MainViewModel负责数据绑定和逻辑。

    • 异步编程:StartAsync使用async/await读取串口。

    • 泛型:DataBuffer缓存历史数据。

    • 事件:OnTemperatureReceived通知UI更新。

    • 数据库:SQLite存储数据,支持历史查询。

  • 运行要求:

    • 安装NuGet包:LiveCharts.Wpf、System.Data.SQLite。

    • 确保串口可用,或使用虚拟串口工具(如VSPD)测试。

  • 扩展建议:

    • 添加报警功能(温度超阈值弹出提示)。

    • 实现历史数据查询界面。

    • 支持多种通信协议(通过工厂模式切换)。


总结

以上示例涵盖了C#高级编程的核心特性,并通过一个完整的上位机项目展示了实际应用。每个代码片段都包含:

  • 详细注释:解释关键逻辑。

  • 异常处理:确保鲁棒性。

  • 上位机场景:结合实际开发需求。

下一步建议

  1. 实践:运行以上代码,修改参数或添加功能(如报警、导出数据)。

  2. 深入某部分:如果需要更详细的某模块(如设计模式或WPF数据绑定),请告诉我,我可以进一步展开。

  3. 项目扩展:尝试开发更复杂的上位机,如支持Modbus协议或多设备管理。

如果您有具体问题或需要某个部分的更深入代码(例如某个设计模式的实现或串口通信的调试技巧),请随时告知!

你可能感兴趣的:(java,c#,开发语言)