编辑
2025-10-05
C#
00

CsvHelper是一个用于读写CSV(逗号分隔值)文件的开源.NET库。它提供了简单而强大的API,使得处理CSV文件变得轻而易举。本文将详细介绍CsvHelper的使用方法,并提供多个实用的例子。

安装

首先,通过NuGet包管理器安装CsvHelper:

C#
Install-Package CsvHelper

image.png

编辑
2025-10-05
C#
00

MediatR是一个轻量级的中介者模式实现库,用于在.NET应用程序中处理进程内消息传递。它有助于降低代码耦合度,提高可维护性和可测试性。本文将深入探讨MediatR的使用方法,并提供多个实际示例。

MediatR的核心概念

在深入示例之前,让我们先了解MediatR的几个核心概念:

  1. 请求(Request): 表示要执行的操作。
  2. 处理程序(Handler): 负责处理特定类型的请求。
  3. 中介者(Mediator): 协调请求和处理程序之间的通信。

安装MediatR

首先,通过NuGet包管理器安装MediatR:

Markdown
dotnet add package MediatR

image.png

编辑
2025-10-05
C#
00

在C#的WinForms应用程序开发中,父子窗体之间的数据传递是一个常见且重要的话题。本文将详细介绍几种实现父子窗体传值的方法,并提供丰富的代码示例。

构造函数传值

这是最简单直接的方法,适用于在创建子窗体时就知道要传递的值的情况。

示例代码

C#
// 父窗体 public partial class ParentForm : Form { public ParentForm() { InitializeComponent(); } private void btnOpenChild_Click(object sender, EventArgs e) { string message = "Hello from Parent!"; ChildForm childForm = new ChildForm(message); childForm.Show(); } } // 子窗体 public partial class ChildForm : Form { public ChildForm(string message) { InitializeComponent(); lblMessage.Text = message; } }

image.png

编辑
2025-10-05
C#
00

S7netplus 是一个开源的库,主要用于.NET环境中与西门子S7系列PLC进行通信。这个库允许开发者使用C#或其他.NET支持的编程语言来读写PLC的数据块、输入输出、标记等,非常适合于工业自动化领域的应用开发。

主要特点

  1. 易于使用:S7netplus 提供了简洁的API,使得开发者可以轻松地连接PLC,读取和写入数据。
  2. 开源:作为一个开源项目,S7netplus 允许开发者查看源代码,也欢迎社区贡献和改进。
  3. 跨平台:基于.NET平台,理论上支持所有.NET能运行的平台,包括Windows, Linux, 和 macOS。

使用S7-PLCSIM Advanced 3.0/4.0/5.0 仿真

image.png

如果启动许可证找不到,在服务中启动

image.png

注意事项

  • IP地址与子网掩码

image.png

  • 在TIA中IP修改与防真中的一样
  • 勾选Connection mechanisms中 Permit access with PUT/GET communication from remote partnet

image.png

  • 项目属性中修改 Protection 勾选Support simulation during block compilation

image.png

  • 确保Siemens PLCSIM Virtual Ethernet Adapter IP与防真IP在一个网段

image.png

  • 控制面板PG/PC
编辑
2025-10-05
C#
00

在C#这样的静态类型语言中,鸭子类型(Duck Typing)通常不像在动态语言中那样自然。鸭子类型的核心思想是:"如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子"—— 即关注对象的行为而非其类型。本文将详细介绍如何在C#中通过缓存和表达式树技术实现高性能的鸭子类型模式,以及这种模式在实际项目中的应用。

鸭子类型与C#的挑战

在传统C#开发中,我们通常通过接口来定义行为规范。但这种方式要求所有类型显式实现接口,缺乏灵活性。使用反射可以解决这个问题,但会带来严重的性能损失。那么如何在保持鸭子类型灵活性的同时,又能获得接近原生代码的性能呢?

高性能鸭子类型的三大技术支柱

我们将使用三种关键技术来实现高性能的鸭子类型:

  1. 反射:用于首次发现和识别类型的能力
  2. 表达式树:用于构建和编译高性能委托
  3. 并发缓存:存储已处理类型的委托,避免重复的反射和编译开销

完整实现案例:智能日志系统

下面我们将构建一个智能日志系统,它可以记录任何拥有GetLogMessage()方法的对象,无需这些对象实现特定接口。

核心实现

C#
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace AppDuck { public class CachedDuckTypingLogger { // 缓存委托:Type => Func<object, string> private readonly ConcurrentDictionary<Type, Func<object, string>> _messageGetterCache = new ConcurrentDictionary<Type, Func<object, string>>(); /// <summary> /// 记录任何具有GetLogMessage方法的对象 /// </summary> public void Log(object item) { try { // 获取日志消息获取器 var messageGetter = GetOrCreateMessageGetter(item.GetType()); if (messageGetter != null) { // 获取并记录消息 string message = messageGetter(item); Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}"); } else { Console.WriteLine($"[ERROR] 无法记录类型为 {item.GetType().Name} 的对象 - 未实现GetLogMessage方法"); } } catch (Exception ex) { Console.WriteLine($"[ERROR] 记录时发生异常: {ex.Message}"); } } /// <summary> /// 从缓存获取或创建消息获取委托 /// </summary> private Func<object, string> GetOrCreateMessageGetter(Type type) { return _messageGetterCache.GetOrAdd(type, t => { // 查找GetLogMessage方法 MethodInfo method = t.GetMethod("GetLogMessage", Type.EmptyTypes); if (method == null || method.ReturnType != typeof(string)) return null; // 创建表达式树 ParameterExpression param = Expression.Parameter(typeof(object), "obj"); UnaryExpression convertedParam = Expression.Convert(param, t); MethodCallExpression methodCall = Expression.Call(convertedParam, method); // 编译表达式树为委托 return Expression.Lambda<Func<object, string>>(methodCall, param).Compile(); }); } } }