FB无法扩展时如何访问VAR_IN_OUT变量?
how to access VAR_IN_OUT variable when FB cannot be extended?
我一直在尝试访问 AXIS_REF_SM3
,即 SM3_Basic.MC_MoveAbsolute
的 Axis
,以便 return 轴的 wDriveId
。
由于 Axis
被声明为 VAR_IN_OUT
变量,我无法使用 .Axis
语法在 FB 外部访问它,因为它会导致编译器抛出
C0178: No external access to VAR_IN_OUT parameter 'Axis' of 'MC_MOVEABSOLUTE'."
错误是有道理的,因为 VAR_IN_OUT
变量不应该可以远程访问。
然后我尝试用 FUNCTION_BLOCK FB_MoveAbsolute EXTENDS SM3_Basic.MC_MoveAbsolute
扩展 FB 并将我自己的方法写入 return PRG 调用 FB_MoveAbsolute
中的 Axis
但我得到以下信息编译器错误
C0283: Function block 'FB_MoveAbsolute': No override possible on Method MC_MoveAbsolute.FB_Init with access specifier FINAL
相反。
有人知道从 SM3_Basic.MC_MoveAbsolute
获取 Axis
的 wDriveId
值的更好方法吗?
或者其他检查 FB 使用哪个轴的方法?
您可以尝试对功能块进行包装:
FUNCTION_BLOCK FINAL FinalBlock
VAR_IN_OUT
someVar: DINT;
END_VAR
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
someVar: DINT;
END_VAR
VAR
_wrapped_obj: POINTER TO FinalBlock;
END_VAR
_wrapped_obj^(someVar := someVar);
//////
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
END_VAR
VAR_IN_OUT
wrappedObj: FinalBlock;
END_VAR
THIS^._wrapped_obj := ADR(wrappedObj);
//////
METHOD GetSomeVarMethod : DINT
GetSomeVarMethod := THIS^.someVar;
//////
METHOD GetWrappedObjP : POINTER TO FinalBlock
GetWrappedObjP := THIS^._wrapped_obj;
PROGRAM SR_Main
VAR
original: FinalBlock;
someVar: DINT := 5;
wrap: Wrapper(original);
getVar: DINT;
END_VAR
wrap(someVar := someVar); // use this instead of "original(someVar := someVar);"
getVar := wrap.GetSomeVarMethod(); // getVar = 5
编辑:如果您要使用引用(或指针),需要注意的一件事是无效引用异常。在这两种情况下你会得到它们:
- 如果在设置之前访问变量:
getVar := wrap.GetSomeVarMethod(); // calling this'll try to access someVar
wrap(someVar := someVar);
- 您忘记了应该使用包装器而不是包装对象:
original(someVar := someVar); // should have called "wrap(someVar := someVar);" instead!
getVar := wrap.GetSomeVarMethod();
要避免这种情况,您可以尝试:
- 访问前检查引用:
METHOD GetSomeVarMethod : DINT
IF __ISVALIDREF(THIS^.someVar) THEN
GetSomeVarMethod := THIS^.someVar;
ELSE
GetSomeVarMethod := -1;
END_IF
或
TYPE OPTIONAL
STRUCT
value: DINT;
error: BOOL;
END_STRUCT
END_TYPE
METHOD GetSomeVarMethod : OPTIONAL
IF __ISVALIDREF(THIS^.someVar) THEN
GetSomeVarMethod.value := THIS^.someVar;
ELSE
GetSomeVarMethod.error := TRUE;
END_IF
然而,如果用户忘记调用 wrap(someVar := someVar);
而只调用 original(someVar := someVar);
那么 someVar 将永远无效。
- 不是将对象传递给包装器,而是让包装器完全创建和管理对象:
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
someVar: DINT;
END_VAR
VAR
// with the 'no_init' attribute, we can let our FB_Init method initialize this object using user given arguments.
// If FinalBlock doesn't have any custom initialization arguments, you can skip this attribute and the FB_init code below.
{attribute 'no_init'}
_wrapped_obj: FinalBlock;
END_VAR
_wrapped_obj(someVar := someVar);
//////
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
// FinalBlock initialization arguments
END_VAR
THIS^._wrapped_obj.FB_Init( (* initialization arguments *) );
无论哪种方式,我都建议您准备好有关如何正确使用包装器并避免错误的文档。
或者,如果您想要将功能块传递给一个函数并访问该函数内的 VAR_IN_OUT 变量的值,您可以将该值与功能块一起传递(因为如果它是 VAR_IN_OUT,无论如何你应该可以访问原始文件):
VAR
original: FinalBlock;
someVar: DINT := 5;
END_VAR
original(someVar := someVar);
getVar := SomeFunction(obj := original, someVar := someVar);
或:
TYPE Bundle :
STRUCT
obj: REFERENCE TO FinalBlock;
someVar: REFERENCE TO DINT;
END_STRUCT
END_TYPE
//////
VAR
original: FinalBlock;
someVar: DINT := 5;
bun: Bundle(obj := original, someVar := someVar);
END_VAR
original(someVar := someVar);
getVar := SomeFunction(bundle := bun);
我一直在尝试访问 AXIS_REF_SM3
,即 SM3_Basic.MC_MoveAbsolute
的 Axis
,以便 return 轴的 wDriveId
。
由于 Axis
被声明为 VAR_IN_OUT
变量,我无法使用 .Axis
语法在 FB 外部访问它,因为它会导致编译器抛出
C0178: No external access to VAR_IN_OUT parameter 'Axis' of 'MC_MOVEABSOLUTE'."
错误是有道理的,因为 VAR_IN_OUT
变量不应该可以远程访问。
然后我尝试用 FUNCTION_BLOCK FB_MoveAbsolute EXTENDS SM3_Basic.MC_MoveAbsolute
扩展 FB 并将我自己的方法写入 return PRG 调用 FB_MoveAbsolute
中的 Axis
但我得到以下信息编译器错误
C0283: Function block 'FB_MoveAbsolute': No override possible on Method MC_MoveAbsolute.FB_Init with access specifier FINAL
相反。
有人知道从 SM3_Basic.MC_MoveAbsolute
获取 Axis
的 wDriveId
值的更好方法吗?
或者其他检查 FB 使用哪个轴的方法?
您可以尝试对功能块进行包装:
FUNCTION_BLOCK FINAL FinalBlock
VAR_IN_OUT
someVar: DINT;
END_VAR
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
someVar: DINT;
END_VAR
VAR
_wrapped_obj: POINTER TO FinalBlock;
END_VAR
_wrapped_obj^(someVar := someVar);
//////
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
END_VAR
VAR_IN_OUT
wrappedObj: FinalBlock;
END_VAR
THIS^._wrapped_obj := ADR(wrappedObj);
//////
METHOD GetSomeVarMethod : DINT
GetSomeVarMethod := THIS^.someVar;
//////
METHOD GetWrappedObjP : POINTER TO FinalBlock
GetWrappedObjP := THIS^._wrapped_obj;
PROGRAM SR_Main
VAR
original: FinalBlock;
someVar: DINT := 5;
wrap: Wrapper(original);
getVar: DINT;
END_VAR
wrap(someVar := someVar); // use this instead of "original(someVar := someVar);"
getVar := wrap.GetSomeVarMethod(); // getVar = 5
编辑:如果您要使用引用(或指针),需要注意的一件事是无效引用异常。在这两种情况下你会得到它们:
- 如果在设置之前访问变量:
getVar := wrap.GetSomeVarMethod(); // calling this'll try to access someVar
wrap(someVar := someVar);
- 您忘记了应该使用包装器而不是包装对象:
original(someVar := someVar); // should have called "wrap(someVar := someVar);" instead!
getVar := wrap.GetSomeVarMethod();
要避免这种情况,您可以尝试:
- 访问前检查引用:
METHOD GetSomeVarMethod : DINT
IF __ISVALIDREF(THIS^.someVar) THEN
GetSomeVarMethod := THIS^.someVar;
ELSE
GetSomeVarMethod := -1;
END_IF
或
TYPE OPTIONAL
STRUCT
value: DINT;
error: BOOL;
END_STRUCT
END_TYPE
METHOD GetSomeVarMethod : OPTIONAL
IF __ISVALIDREF(THIS^.someVar) THEN
GetSomeVarMethod.value := THIS^.someVar;
ELSE
GetSomeVarMethod.error := TRUE;
END_IF
然而,如果用户忘记调用 wrap(someVar := someVar);
而只调用 original(someVar := someVar);
那么 someVar 将永远无效。
- 不是将对象传递给包装器,而是让包装器完全创建和管理对象:
FUNCTION_BLOCK Wrapper
VAR_IN_OUT
someVar: DINT;
END_VAR
VAR
// with the 'no_init' attribute, we can let our FB_Init method initialize this object using user given arguments.
// If FinalBlock doesn't have any custom initialization arguments, you can skip this attribute and the FB_init code below.
{attribute 'no_init'}
_wrapped_obj: FinalBlock;
END_VAR
_wrapped_obj(someVar := someVar);
//////
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
// FinalBlock initialization arguments
END_VAR
THIS^._wrapped_obj.FB_Init( (* initialization arguments *) );
无论哪种方式,我都建议您准备好有关如何正确使用包装器并避免错误的文档。
或者,如果您想要将功能块传递给一个函数并访问该函数内的 VAR_IN_OUT 变量的值,您可以将该值与功能块一起传递(因为如果它是 VAR_IN_OUT,无论如何你应该可以访问原始文件):
VAR
original: FinalBlock;
someVar: DINT := 5;
END_VAR
original(someVar := someVar);
getVar := SomeFunction(obj := original, someVar := someVar);
或:
TYPE Bundle :
STRUCT
obj: REFERENCE TO FinalBlock;
someVar: REFERENCE TO DINT;
END_STRUCT
END_TYPE
//////
VAR
original: FinalBlock;
someVar: DINT := 5;
bun: Bundle(obj := original, someVar := someVar);
END_VAR
original(someVar := someVar);
getVar := SomeFunction(bundle := bun);