概念奠基:is-a 和 can-do
面向对象中,代码复用有两个维度:纵向的"是什么"和横向的"能做什么"。
压力传感器 是一个 传感器
纵向关系:子类复用父类的数据和行为
这个传感器 可以自检
横向关系:一个类可以拥有多种"能力"
在 LabVIEW 2020 之前,如果你想让一个类同时具备"可校准"和"可诊断"的能力,只能靠复杂的组合或抽象类变通。从 LabVIEW 2020 开始,Interface 让这个问题彻底解决——一个类 = 1 个父类 + N 个接口,和 C# 完全相同。
继承(Inheritance):纵向的"是什么"
继承在两个平台上的语法对比如下:
2.创建 Temperature Sensor.lvclass
3.右键 → Properties → Inheritance → Change Parent Class → 选择 Sensor.lvclass
4.子类自动继承父类的所有数据和 VI,需要重写的方法用 Create VI for Override
// 基类
public class Sensor
{
public string Name { get; set; }
public double Reading { get; set; }
// virtual = 子类可以重写(对标 LabVIEW Dynamic Dispatch VI)
public virtual string GetInfo()
=> $"传感器 \"{Name}\" 读数: {Reading}";
}
// 子类
// : Sensor = "继承自 Sensor"(对标 Change Parent Class)
public class TemperatureSensor : Sensor
{
public string Unit { get; set; } = "°C";
// override = 重写父类方法(对标 Create VI for Override)
public override string GetInfo()
=> $"温度传感器 \"{Name}\" = {Reading}{Unit}";
}“共同规则:两个平台都只允许单继承(一个类只能有一个父类)。这是为了避免"菱形继承"问题——如果两个父类有同名方法,编译器无法判断该调用哪一个。”
接口(Interface):横向的"能做什么"
接口只声明方法签名,不包含数据和实现。它解决的问题是:如何让不相关的类共享同一套行为契约。
// 声明接口(只有方法签名,没有实现、没有字段)
public interface ICalibratable
{
void Calibrate(); // 校准
bool IsCalibrated { get; } // 只读属性:是否已校准
}
public interface IDiagnosable
{
string RunDiagnostics(); // 自检,返回诊断结果
}命名习惯差异:
- C#:接口名以大写 I 开头(ICalibratable),这是 .NET 的传统
- LabVIEW:不推荐 I 前缀,因为 LabVIEW 用图标区分类和接口(实心立方体 = 类,线框立方体 = 接口),命名区分不必要
LabVIEW 2020+ Interface 详解
LabVIEW 2020 引入的 Interface 是这十年来 LV OOP 最重要的更新。根据 NI 官方文档和社区共识,核心事实如下:
Interface 是什么?
Interface 是什么?
- 可以理解为"没有私有数据控件的类"(a class without a private data control)
- 它声明对象"能扮演什么角色",但不定义如何扮演
- 文件扩展名仍是 .lvclass,和普通类一样
- 在项目浏览器中,类用实心立方体图标,接口用线框立方体图标
单继承 + 多接口的规则
这和 C# 完全一致:
- 1 个父类:通过 Change Parent Class 选择(只能选一个)
- 多个接口:通过 Change Parent Interfaces 多选(想选几个选几个)
- 接口也可以继承自其他接口
- 一个类实现的所有接口方法都必须 override(Create VI for Override)
解决的典型问题:硬件抽象层(HAL)
NI 引入 Interface 最典型的场景是硬件抽象。以一个 SMU(Source Measurement Unit)为例——它既能源(Supply)又能测(DMM):

左边是 LabVIEW 2020 之前的困境:SMU 既"是一个" Supply 又"是一个" DMM,但只能选一个父类。右边的 Interface 方案完美解决——Supply 和 DMM 变成接口,SMU 继承 1 个普通类 + 2 个接口,自由地同时扮演两种角色。
完整对比表
| 特性 | LabVIEW 2020+ | C# |
|---|---|---|
| 父类继承 | Properties → Inheritance → Change Parent Class(只能 1 个) | class X : Parent |
| 接口声明 | 右键项目 → New → Interface | interface IName { } |
| 接口方法 | New VI → Dynamic Dispatch Template(只有连线板,无实现) | 只写方法签名,不带方法体 |
| 接口无数据 | 没有 Private Data Control | 不能声明字段 |
| 实现多个接口 | Properties → Inheritance → Change Parent Interfaces → 多选 | class X : Parent, I1, I2, I3 |
| 重写虚方法 | 右键 → Create VI for Override | override 关键字 |
| 运行时类型判断 | Preserve Run-Time Class + To More Specific Class | if (obj is IName x) |
| 文件扩展名 | .lvclass(接口和类共用) | .cs |
| 视觉区分 | 实心立方体 = 类,线框立方体 = 接口 | I 前缀 = 接口 |
多态:用父类/接口类型统一操作子类
继承和接口的最终价值在于多态——你可以用父类或接口的引用来操作任意子类对象,而不用关心运行时它具体是哪一个子类。
场景1:用父类类型遍历所有子类
// 所有传感器,不管什么类型,都是 Sensor
List<Sensor> sensors = new()
{
new TemperatureSensor { Name = "TC-01", Reading = 23.5 },
new PressureSensor { Name = "P-02", Reading = 101.3 },
new PrecisionSensor { Name = "PS-A", Reading = 42.0 }
};
// GetInfo() 会自动路由到正确的子类实现(Dynamic Dispatch)
foreach (var s in sensors)
Console.WriteLine(s.GetInfo());
// 输出:
// 温度传感器 "TC-01" = 23.5°C
// 压力传感器 "P-02" = 101.3kPa
// 精密传感器 "PS-A" 读数: 42.000在 LabVIEW 中完全等价:创建一个 Sensor 类型的数组,把三个子类对象放入,用 For Loop 遍历时调用 DD VI 的 GetInfo,LabVIEW 同样会根据实际类型自动路由。
场景2:用接口类型按"能力"操作
// 只对有校准能力的传感器执行校准
foreach (var s in sensors)
{
if (s is ICalibratable c) // 运行时判断:这个对象能校准吗?
{
c.Calibrate(); // 能 → 校准它
Console.WriteLine($" \"{s.Name}\" 已校准");
}
else
{
Console.WriteLine($" \"{s.Name}\" 不支持校准");
}
}
// 输出:
// "TC-01" 不支持校准
// "P-02" 不支持校准
// "PS-A" 已校准在 LabVIEW 中:用 Preserve Run-Time Class + To More Specific Class 判断对象是否为某个接口类型,然后连到接口线操作。
场景3:把对象"降维"到接口类型,限制可用的方法
var ps = new PrecisionSensor { Name = "PS-A", Reading = 42.0 };
// 把对象当作 ICalibratable 使用——只能用 Calibrate() 和 IsCalibrated
ICalibratable cal = ps;
cal.Calibrate();
// cal.Name ← 编译错误!ICalibratable 没有 Name
// 把对象当作 IDiagnosable 使用——只能用 RunDiagnostics()
IDiagnosable diag = ps;
Console.WriteLine(diag.RunDiagnostics());这种"视角切换"在 LabVIEW 中就是:同一个类对象,用不同类型的 Wire 连线,可用方法不同。
总结
LabVIEW 2020 引入 Interface 之后,两个平台的 OOP 模型已经完全对齐——单继承 + 多接口,功能和约束一致。
| 记忆口诀 | 含义 | 示例 |
|---|---|---|
| is-a | 继承:子类 是 父类的一种 | TemperatureSensor is a Sensor |
| can-do | 接口:类 能做 某件事 | PrecisionSensor can Calibrate |
| 1 + N | 1 个父类 + N 个接口 | class X : Parent, I1, I2 |
如果你在 LabVIEW 2020+ 中已经用过 Interface,那么 C# 的 interface + : 语法对你来说就是纯粹的拼写转换。底层思想完全相同,没有任何新概念需要学习。