在C#中能否通过模板生成大量带错误处理的相似硬件驱动属性?
批量生成带错误处理的Double属性方案
当然可以实现你想要的模板化生成!最直接高效的方式是用T4文本模板来批量生成这些重复的属性代码——既不用手动复制粘贴,还能保证所有错误处理逻辑一致,后续维护也只需要修改模板或者配置列表就行。
方案一:T4模板生成静态属性(推荐)
T4是Visual Studio内置的代码生成工具,能帮你把配置好的属性列表自动转换成完整的C#属性代码。
步骤1:创建T4模板文件
在你的项目里添加一个新的文本模板(后缀为.tt),比如命名为DeviceDoubleProperties.tt,然后把下面的代码粘贴进去:
<#@ template language="C#" #> <#@ output extension=".cs" #> using System; // 这里替换成你实际的设备类名 public partial class SerialDevice { private readonly YourUnderlyingDeviceType _device; // 假设你的设备类已有构造函数,这里仅作示例 public SerialDevice(YourUnderlyingDeviceType device) { _device = device; } // 👇 在这里添加/修改你的属性配置:属性名、对应的Set方法、Get方法 <# var propertyConfigs = new[] { new { PropName = "Acceleration", SetMethod = "AC_Set", GetMethod = "AC_Get" }, new { PropName = "Velocity", SetMethod = "VEL_Set", GetMethod = "VEL_Get" }, new { PropName = "Position", SetMethod = "POS_Set", GetMethod = "POS_Get" }, // 可以继续添加更多属性,比如: // new { PropName = "Torque", SetMethod = "TOR_Set", GetMethod = "TOR_Get" }, }; #> <#-- 自动生成每个属性的代码 --> <# foreach (var config in propertyConfigs) { #> public double <#= config.PropName #> { get { int errorCode = _device.<#= config.GetMethod #>(out double value, out string errorString); if (errorCode != 0) throw new Exception($"Failed to get {config.PropName}: {errorString}"); return value; } set { int errorCode = _device.<#= config.SetMethod #>(value, out string errorString); if (errorCode != 0) throw new Exception($"Failed to set {config.PropName}: {errorString}"); } } <# } #> }
步骤2:适配你的实际代码
- 把
SerialDevice替换成你自己的设备类名 - 把
YourUnderlyingDeviceType替换成底层驱动库的设备类型 - 在
propertyConfigs数组里添加所有需要生成的属性配置
步骤3:生成代码
保存模板文件后,Visual Studio会自动生成对应的.cs文件(比如DeviceDoubleProperties.cs),里面就是你想要的所有带错误处理的属性代码,直接就能用!
这种方式的好处是生成的是静态编译的代码,和手动写的属性完全一样,没有运行时开销,而且编译时就能检查方法名是否正确。
方案二:用委托封装通用属性类(运行时方式)
如果你不想用代码生成,也可以封装一个通用的属性类,通过委托绑定底层的Set/Get方法。不过这种方式访问属性时需要多一层.Value调用:
using System; public class DoubleDeviceProperty { private readonly Action<double> _setAction; private readonly Func<double> _getFunc; public DoubleDeviceProperty( Action<double, out int, out string> setMethod, Func<out double, out int, out string> getMethod) { // 封装Set方法,自动处理错误 _setAction = value => { int errorCode = setMethod(value, out string errorString); if (errorCode != 0) throw new Exception(errorString); }; // 封装Get方法,自动处理错误 _getFunc = () => { int errorCode = getMethod(out double value, out string errorString); if (errorCode != 0) throw new Exception(errorString); return value; }; } public double Value { get => _getFunc(); set => _setAction(value); } }
然后在你的设备类里使用:
public class SerialDevice { private readonly YourUnderlyingDeviceType _device; public DoubleDeviceProperty Acceleration { get; } public DoubleDeviceProperty Velocity { get; } public DoubleDeviceProperty Position { get; } public SerialDevice(YourUnderlyingDeviceType device) { _device = device; Acceleration = new DoubleDeviceProperty(_device.AC_Set, _device.AC_Get); Velocity = new DoubleDeviceProperty(_device.VEL_Set, _device.VEL_Get); Position = new DoubleDeviceProperty(_device.POS_Set, _device.POS_Get); } }
使用时需要这样访问:
var device = new SerialDevice(underlyingDevice); // 获取值 double accel = device.Acceleration.Value; // 设置值 device.Acceleration.Value = 10.5;
这种方式的灵活性更高,但不如T4生成的静态属性直观,而且有轻微的委托调用开销。
总结
如果只是批量生成固定模式的属性,T4模板是最优选择——代码简洁、无运行时开销、维护方便。如果需要更动态的属性管理(比如运行时添加属性),再考虑委托封装的方式。
内容的提问来源于stack exchange,提问作者Eric Hoffstetter
相关产品推荐
相关产品推荐

