假设我有一个抽象的功能块AValve
,我扩展了各种类型的阀门。我将AValve
扩展为BasicValve
来实现它。我还有一个函数块,它接受AValve
数组,看起来像这样
FUNCTION_BLOCK ValveDispatch
VAR_IN_OUT
valves : ARRAY[*] OF AVALVE;
END_VAR
如果我试图传递一个BasicValve
数组到这个函数块,我遇到了:
无法转换类型'ARRAY [0..][5]
返回VAR_IN_OUT ' values '的值
认为也许codesys只是不能同时处理扩展类型和可变长度数组,我试过做一个集合长度数组作为输入,只是为了测试,因为我需要可变长度。这样做会产生一个稍微不同的错误,但似乎意味着相同的事情:
类型的数组(0 . .[5]的BasicValve'不等于类型'ARRAY [0..][5] OF valve ' OF VAR_IN_OUT ' values
我有办法让这个工作吗?将单个扩展对象传递到期望其基类型的输入中可以正常工作,但似乎不支持对数组这样做。
您看到的问题实际上可以归结为一个非常简单的点,数组是值数据类型.
也就是说,当你试图通过VAR_IN_OUT
传递ARRAY [*] OF FB_Ext
时,你实际上是在创建一个全新的数据类型ARRAY [*] OF FB_Ext
,它不扩展ARRAY [*] OF FB_Base
。
如果你在ST中查看位级别的数组,问题变得非常清楚,数组本身的大小为ElementSize * ElementCount
,因此试图将更大的数据类型FB_Ext
强制到FB_Base
的较小数据空间中是不可能在不搞砸一切的情况下工作的。
所以你必须用指针或接口来做这个处理。
TLDR:你想做的事在st是不可能的
这本来是一个注释,但是它有点超出了大小限制。作为wiki发布
简短的回答:对于Var_In_Out
,这是不可能的。Var_in_out
是一种引用调用。在TwinCAT中,引用总是有严格的类型绑定。
我的第一种方法是用简单的var_input
接口指针来解决这个问题。接口包含您所移交的字段的大小和类型(如Array[*]
所做的)。但我不确定是否允许派生接口指针切换。也许你必须移交基本接口,并在某个地方手动与__TCQUERYINTERFACE
进行接口转换。
我将在这里为我自己的问题添加一个答案,但暂时不接受它,以防有人有秘密要泄露,哈哈。
实际上,据我所知,将Array of Derived Type
传递给Array of BasicType
的模式根本不受支持。通过VAR_IN_OUT
或其他输入类型。你甚至不能把一个分配给另一个。最好我能告诉Codesys不尊重继承时比较数组彼此,但将如果你比较数组的一个特定的索引到一个对象。我想出了两种我不喜欢但应该可行的方法。
如果你要传递接口,你可以像这样在调用函数块的头文件中构建数组:
VAR
aFB : ARRAY[0..2] of ExtendedFB;//implements IExtended, which extends IBasic
aInterface : ARRAY[0..2] OF IBasic := [aFB[0], aFB[1],aFB[2]];
END_VAR
当涉及到扩展fb而不是接口时,这将不太有效。在这种情况下,我必须使用指针,像这样:
VAR
aFB: ARRAY[0..2] of ExtendedFB;//extends AbstractFB
apFB : Array[0..2] of Pointer to AbstractFB := [ADR(afb[0]), ADR(afb[1]), ADR(afb[2])];
END_VAR
TL;DR不是将Array of ExtendedType
传递到期望Array of BasicType
或Reference to Array of BasicType
的输入,您可以使用ExtendedType
对象手动构建Array of BasicType
,每次一个索引并传递它,而不会引起编译器的抱怨。不幸的是,如果不使用接口,就只能使用指针,因为如果不实例化函数块,就不能创建函数块数组。