-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Type of issue
- Bug
- Enhancement
- Compliance
- Question
- Help wanted
Current Behavior
- Overrides of
NodeState.FindChild(ISystemContext context, QualifiedName browseName, bool createOrReplace, BaseInstanceState replacement)specified in nested classes break base logic (defined at base class NodeState): arguments are a handled in a different way. - Generated implementations (by ModelCompiler) of overrides of the same method
FindChildalso break the logic different at NodeState.FindChild. - Comments of
NodeState.FindChild(ISystemContext context, QualifiedName browseName, bool createOrReplace, BaseInstanceState replacement)do not correspond to its logic. - NodeState.FindChild() returns null if provided
replacementis just added (but do not replace existing child).
Take you attention that logic of NodeState.FindChild() is correct taking into acount its usage by method NodeState.ReplaceChild() . The overrides in the nested types do not allow to replace the child using that method.
Logic of handling of createOrReplace== true:
- in NodeState: existing child (instance of the corresponding node-type) is replaced by provided
replacementor by created instance or just set child with replacement/created if no actual one; - in the nested classes of NodeState (including generated by ModelCompiler): existing child (instance of the corresponding node-type) is NOT replaced or just set the child with provided
replacementor by created instance if no actual child.
Expected Behavior
- Logic of handling of
createOrReplace== true in overrides ofNodeState.FindChild(ISystemContext context, QualifiedName browseName, bool createOrReplace, BaseInstanceState replacement):
existing child (instance of the corresponding node-type) is replaced by providedreplacementor by the created instance, the child is set by replacement/created instance if no actual child. - if createOrReplace == true then
replacementor the created instance should be returned always from the FindChild().
Environment
- Nuget Version: all up to 1.05
- Component: ServerAnything else?
simplified/cropped existing implementation of NodeState.ReplaceChild:
public virtual void ReplaceChild(ISystemContext context, BaseInstanceState child)
{
// some validation code
FindChild(context, child.BrowseName, true, child);
}
Here createOrReplace=true and the code clearly shows that FindChild() SHOULD replace existing child with the new provided value or just set the child by the provided value if the child is null now.
Simplified/cropped code of NodeState.FindChild() with ITS OWN BUG:
protected virtual BaseInstanceState FindChild(ISystemContext context, QualifiedName browseName, bool reateOrReplace, BaseInstanceState replacement)
{
// some validation
// cropped code to simplify in the Issue
for (int ii = 0; ii < m_children.Count; ii++)
{
BaseInstanceState child = m_children[ii];
if (browseName == child.BrowseName)
{
if (createOrReplace && replacement != null)
m_children[ii] = child = replacement;
return child;
}
}
if (createOrReplace && replacement != null)
{
AddChild(replacement);
// BUG: return is missed
// next line sould be added:
return replacement;
}
return null;
}
Generally logic corresponds to ReplaceChild and common sense. Note: new instance of a child cannot be created by NodeState itself because child's type is unknown - its ok for NodeState.
Sample of the corresponding code from the standard nested class: part of DialogConditionState.FindChild():
switch (browseName.Name)
{
case Opc.Ua.BrowseNames.DialogState:
{
if (createOrReplace)
{
if (DialogState == null)
{
if (replacement == null)
DialogState = new TwoStateVariableState(this);
else
DialogState = (TwoStateVariableState)replacement;
}
}
instance = DialogState;
break;
}
// some code
if (instance != null)
return instance;
return base.FindChild(context, browseName, createOrReplace, replacement);
Here existing child DialogState is not replaced if it is not null even if argument createOrReplace == true. So DialogConditionState.ReplaceChild(context, some_new_value_for_DialogState) just returns existing DialogState and ignores provided new value.
Additional question
Is it generally correct that ReplaceChild() may set named property ( explicitly defined children) in the instance of a nested class of NodeState but AddChild() never set the named property even if both methods are called with the same argument?