1. C#语言概述与核心特性
C#(读作C Sharp)是微软在2000年推出的一种面向对象的编程语言,作为.NET框架的主力语言,它融合了C++的强大功能和Java的简洁特性。经过20多年的发展,C#已经从最初的Windows桌面开发语言成长为跨平台、多场景的全能型语言。
C# 7.0引入的模式匹配、本地函数等语法糖让代码更加简洁。在实际项目中,我特别喜欢使用元组返回多个值,这比传统的out参数优雅得多。比如处理坐标转换时:
csharp复制(double x, double y) TransformCoordinates(double inputX, double inputY)
{
return (inputX * scaleFactor, inputY * scaleFactor);
}
// 调用方式
var (resultX, resultY) = TransformCoordinates(10, 20);
经验之谈:虽然语法糖让代码更简洁,但在团队协作项目中要适度使用,确保代码可读性优先。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C#上位机开发实战
上位机开发是C#的经典应用场景,特别是在工业自动化领域。通过串口通信或以太网协议(如Modbus TCP)与PLC等设备交互,构建监控系统。
2.1 串口通信实现
System.IO.Ports命名空间提供了完整的串口操作类。开发时需要注意:
- 波特率设置必须与设备一致
- 数据位、停止位和校验位的配置
- 接收数据时的缓冲区处理
csharp复制SerialPort mySerialPort = new SerialPort("COM3")
{
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
StopBits = StopBits.One
};
mySerialPort.DataReceived += (sender, e) =>
{
string data = mySerialPort.ReadExisting();
// 处理接收到的数据
};
2.2 多线程处理技巧
上位机常需要同时处理UI响应和设备通信,多线程是必须掌握的技能。C#提供了多种方案:
| 技术方案 | 适用场景 | 注意事项 |
|---|---|---|
| Thread | 长时间后台任务 | 需要手动管理生命周期 |
| Task | 异步操作 | 推荐使用async/await语法 |
| BackgroundWorker | UI相关后台任务 | 已逐渐被Task替代 |
csharp复制// 现代C#推荐写法
private async void btnStart_Click(object sender, EventArgs e)
{
try
{
await Task.Run(() => {
// 执行耗时操作
});
}
catch (Exception ex)
{
// 异常处理
}
}
3. 图形界面与可视化开发
3.1 WinForm高级技巧
虽然WPF是微软主推的UI框架,但WinForm因其简单易用仍在很多项目中广泛使用。一些实用技巧:
- 双缓冲技术解决闪烁问题:
csharp复制this.SetStyle(
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
- 自定义控件开发:继承现有控件扩展功能
- GDI+绘图:实现数据可视化(如绘制瀑布图)
3.2 使用OpenTK实现3D交互
OpenTK是.NET平台的OpenGL封装,适合开发3D可视化应用。基本使用流程:
- 安装NuGet包:OpenTK、OpenTK.GLControl
- 创建GLControl实例
- 重写OnRenderFrame等方法
csharp复制protected override void OnRenderFrame(FrameEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.Begin(PrimitiveType.Triangles);
GL.Vertex2(-0.5f, -0.5f);
GL.Vertex2(0.5f, -0.5f);
GL.Vertex2(0.0f, 0.5f);
GL.End();
SwapBuffers();
}
4. 网络通信与协议实现
4.1 WebSocket服务端开发
使用System.Net.WebSockets命名空间可以轻松实现WebSocket服务:
csharp复制public async Task StartWebSocketServer(HttpListenerContext context)
{
WebSocketContext wsContext = await context.AcceptWebSocketAsync(null);
WebSocket webSocket = wsContext.WebSocket;
byte[] buffer = new byte[1024];
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
// 处理消息...
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
4.2 SignalR实时通信
SignalR简化了实时Web功能的开发,支持WebSocket、Server-Sent Events等多种传输方式。典型应用场景包括聊天室、实时监控等。
csharp复制// Hub类定义
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
// 客户端调用
connection = new HubConnectionBuilder()
.WithUrl("/chatHub")
.Build();
connection.On<string, string>("ReceiveMessage", (user, message) => {
// 处理接收到的消息
});
await connection.StartAsync();
await connection.InvokeAsync("SendMessage", userName, message);
5. 高级编程技巧
5.1 反射与动态编程
System.Reflection命名空间提供了在运行时检查类型信息的能力。虽然反射功能强大,但性能开销较大,应谨慎使用。
csharp复制Type type = typeof(MyClass);
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("MyMethod");
method.Invoke(instance, new object[] { "参数" });
// 更高效的替代方案:表达式树或Emit
5.2 委托与事件
委托是C#实现回调机制的核心,事件基于委托实现发布-订阅模式。
csharp复制public class PrinterMonitor
{
public delegate void PrinterEventHandler(string message);
public event PrinterEventHandler PrinterStatusChanged;
public void CheckPrinterStatus()
{
// 检测打印机状态
if(/* 异常状态 */)
{
PrinterStatusChanged?.Invoke("打印机异常");
}
}
}
// 使用
var monitor = new PrinterMonitor();
monitor.PrinterStatusChanged += (msg) => Console.WriteLine(msg);
5.3 LINQ与XML处理
LINQ to XML提供了优雅的XML操作方式:
csharp复制XDocument doc = XDocument.Load("data.xml");
// 查询
var items = from element in doc.Descendants("Item")
where (int)element.Attribute("id") > 100
select new {
Id = (int)element.Attribute("id"),
Name = element.Value
};
// 创建
XElement newElement = new XElement("NewItem",
new XAttribute("id", 200),
"Item Content");
doc.Root.Add(newElement);
doc.Save("updated.xml");
6. 性能优化与调试
6.1 内存管理
虽然C#有垃圾回收机制,但不当的内存使用仍会导致问题:
- 避免频繁的大对象分配
- 及时释放非托管资源(实现IDisposable接口)
- 注意事件订阅导致的内存泄漏
csharp复制// 正确释放资源的模式
public class ResourceHolder : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// 释放托管资源
}
// 释放非托管资源
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~ResourceHolder()
{
Dispose(false);
}
}
6.2 多线程调试技巧
多线程程序调试是开发中的难点,Visual Studio提供了强大的工具:
- 并行堆栈窗口:查看所有线程的调用堆栈
- 并行任务窗口:监控Task的运行状态
- 线程标记:为线程设置颜色标记便于区分
调试心得:在多线程环境中,使用lock时要特别注意死锁问题。我通常会为所有锁对象定义一个明确的获取顺序,并在代码中添加注释说明。
7. 项目实战:人脸识别工具开发
结合OpenCVSharp4和WinForm,我们可以开发一个简单的人脸识别工具:
- 安装NuGet包:OpenCvSharp4、OpenCvSharp4.runtime.win
- 加载预训练的人脸检测模型
- 实现视频捕获和人脸识别逻辑
csharp复制// 核心识别代码
using (var capture = new VideoCapture(0))
using (var window = new Window("人脸识别"))
using (var faceCascade = new CascadeClassifier("haarcascade_frontalface_default.xml"))
{
while (true)
{
using (var frame = new Mat())
{
capture.Read(frame);
if (frame.Empty()) break;
var faces = faceCascade.DetectMultiScale(
frame, 1.1, 2, HaarDetectionType.ScaleImage);
foreach (var face in faces)
{
frame.Rectangle(face, Scalar.Red, 2);
}
window.ShowImage(frame);
if (Cv2.WaitKey(1) == 27) break; // ESC退出
}
}
}
开发这类工具时需要注意:
- 模型文件需要随应用程序一起分发
- 视频捕获的异常处理(如摄像头不可用)
- 性能优化(如降低检测频率提高流畅度)
8. 部署与跨平台开发
8.1 应用程序部署
.NET Core/5+引入了独立的发布模式,简化了部署:
bash复制dotnet publish -c Release -r win-x64 --self-contained true
关键选项:
- -r:指定目标运行时(如linux-x64)
- --self-contained:是否包含运行时
8.2 使用Avalonia实现跨平台UI
Avalonia是.NET的跨平台UI框架,支持Windows、Linux、macOS:
- 创建项目:
bash复制dotnet new avalonia.app -o MyAvaloniaApp
- 主窗口定义:
csharp复制public class MainWindow : Window
{
public MainWindow()
{
this.Content = new StackPanel
{
Children =
{
new TextBlock { Text = "欢迎使用Avalonia!" },
new Button { Content = "点击我" }
}
};
}
}
- 平台特定代码处理:
csharp复制if (OperatingSystem.IsWindows())
{
// Windows特有实现
}
else if (OperatingSystem.IsLinux())
{
// Linux特有实现
}
9. 与硬件设备的交互
9.1 与汇川PLC通讯
通过Modbus协议与PLC通讯的典型流程:
- 安装NModbus4等Modbus库
- 建立TCP连接或串口连接
- 读写寄存器
csharp复制// 创建Modbus TCP主站
var factory = new ModbusFactory();
using (var master = factory.CreateMaster(tcpClient))
{
// 读取保持寄存器
ushort[] registers = master.ReadHoldingRegisters(1, 0, 10);
// 写入单个寄存器
master.WriteSingleRegister(1, 5, 1234);
}
9.2 打印机状态监控
使用WMI查询打印机状态:
csharp复制using System.Management;
var query = new SelectQuery("SELECT * FROM Win32_Printer");
var searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject printer in searcher.Get())
{
string name = printer["Name"].ToString();
string status = printer["PrinterStatus"].ToString();
if (status != "3") // 3表示就绪
{
// 处理打印机异常
}
}
10. 现代C#特性应用
10.1 模式匹配
C# 7.0引入的模式匹配让类型检查和转换更加简洁:
csharp复制public static double ComputeArea(object shape)
{
return shape switch
{
Circle c => Math.PI * c.Radius * c.Radius,
Rectangle r => r.Width * r.Height,
Triangle t => t.Base * t.Height / 2,
_ => throw new ArgumentException("未知形状")
};
}
10.2 记录类型(Record)
C# 9.0引入的记录类型简化了不可变模型的创建:
csharp复制public record Person(string FirstName, string LastName);
// 使用
var person = new Person("张", "三");
var (firstName, lastName) = person; // 解构
10.3 顶级语句
C# 9.0允许省略类定义和Main方法,简化小程序:
csharp复制// 直接编写执行代码
Console.WriteLine("Hello World!");
// 异步主方法
await Task.Delay(1000);
Console.WriteLine("延迟1秒后输出");
在实际项目中,我通常会将这些现代特性与传统写法结合使用,根据团队熟悉度和项目复杂度做出平衡。对于新项目,特别是使用.NET 6+的,可以大胆采用新特性提高开发效率;而对于维护老项目,则需要考虑兼容性和团队适应成本。
