如何通过C# ADS访问TwinCAT3中动态创建的子类对象变量
问题描述
我正在用TwinCAT3和C# ADS开发HMI项目,出于架构设计需要想使用TwinCAT的面向对象编程。但作为新手,我不知道怎么通过ADS句柄把嵌套子类对象连接到HMI。
父功能块代码:
//Example FUNCTION_BLOCK FB_Parent VAR iParentVariable: INT; END_VAR
继承自父类的子功能块:
//Example FUNCTION_BLOCK FB_Child EXTENDS FB_Parent VAR iChildVariable: INT; END_VAR
程序里定义了一个FB_Parent类型的数组,收到自定义HMI(C#)的初始化指令时,动态创建FB_Child对象:
// Example fbChild := __NEW(FB_Child); array[0] := fbChild^; __DELETE(fbChild);
问题是在C# HMI里无法创建句柄访问子类变量:
client = new AdsClient { Timeout = 500 }; client.Connect(parameters.AmsNetID, parameters.AdsPort); handler = client.CreateVariableHandle("PRG_MAIN.arrConveyors[0].iChildVariable");
我试过两种修改数组定义的方式,但都没用:
- 使用
POINTER OF FB_Parent - 用接口替代父类
请问怎么在TwinCAT里继续用面向对象和动态对象创建,同时通过C# ADS访问子类变量?
解决方案
1. 避免值拷贝,改用指针数组存储动态对象
你当前代码里的array[0] := fbChild^是把FB_Child的值拷贝到FB_Parent类型的数组元素中,这会切片子类的特有属性(比如iChildVariable),导致ADS无法识别这些属性。正确做法是用指针数组存储对象引用:
首先定义指针数组:
VAR_GLOBAL arrConveyors: ARRAY[0..N] OF POINTER TO FB_Parent; END_VAR
动态创建对象时,直接存储指针,不要做值拷贝,也不要立即调用__DELETE(否则对象会被销毁):
// 正确的动态创建逻辑 fbChild := __NEW(FB_Child); arrConveyors[0] := fbChild; // 存储指针,不拷贝值 // 不要在这里调用__DELETE,对象需要保持存在以被HMI访问
2. ADS访问子类属性的正确路径
ADS访问指针指向的对象属性时,需要用^表示指针解引用。C#中的变量路径要修改为:
handler = client.CreateVariableHandle("PRG_MAIN.arrConveyors[0]^.iChildVariable");
3. 进阶:用接口实现类型安全的属性暴露
如果需要更严谨的类型检查,可以定义包含子类属性的接口,让子类实现该接口:
INTERFACE IChild VAR_OUTPUT iChildVariable: INT; END_VAR END_INTERFACE FUNCTION_BLOCK FB_Child EXTENDS FB_Parent IMPLEMENTS IChild VAR iChildVariable: INT; END_VAR
此时ADS访问路径和指针方式一致,既保留面向对象架构,又能明确暴露HMI需要访问的属性。
4. 关键注意事项
- 动态创建的对象必须在程序生命周期内保持存在,不要提前
__DELETE,否则ADS访问会报错。 - 若要销毁对象,需先通知HMI停止访问,再调用
__DELETE并将数组中的指针置为0。 - TwinCAT ADS不支持直接的多态属性访问,必须通过指针解引用或接口明确定位子类属性。
内容的提问来源于stack exchange,提问作者Schupbach Loïc
相关产品推荐
相关产品推荐

