跳到主要内容

Call

前置 / 配套
  • 数据类型 Variant 是入参 / 出参的容器.
  • 找方法 NodeId 用 Browsefilter: NodeClass.Method.

签名

public IReadOnlyList<Variant> Call(
string objectNodeId,
string methodNodeId,
params Variant[] inputs);
参数说明
objectNodeId方法所在 Object 节点
methodNodeId方法本身 NodeId
inputs入参 Variant 数组 (可空)

返回 IReadOnlyList<Variant> 输出参数列表.


内存所有权 (重要)

返回列表里每个 Variant 都持有 native handle, 必须 Dispose, 否则泄漏 native Variant 内存.

推荐写法:

var outputs = ua.Call(objId, mtdId, args);
foreach (var v in outputs) using (v) { /* 用 v.AsXxx 等 */ }

或显式:

var outputs = ua.Call(objId, mtdId, args);
try { /* 用 outputs[i] */ }
finally { foreach (var v in outputs) v.Dispose(); }

例子

// 调 Calculator.Add(3, 4)
var inputs = new Variant[] { new Variant(3), new Variant(4) };
var outputs = ua.Call(
objectNodeId: "ns=2;s=Calculator",
methodNodeId: "ns=2;s=Calculator.Add",
inputs);

foreach (var v in outputs) using (v)
Console.WriteLine($"sum = {v.AsInt32}");

异常

异常含义
OpcUaException(BadNodeIdInvalid)NodeId 解析失败
OpcUaException(BadCommunicationError)Transport 错
OpcUaException(BadMethodInvalid)该 NodeId 不是 Method
OpcUaException(BadInvalidArgument)入参类型 / 个数不符
OpcUaException(BadUserAccessDenied)无权限调
OpcUaException(BadXxx)方法返回非 Good 业务码

业务级失败 (方法返回非 Good) 也抛异常, ex.StatusCode 即业务码.


找方法的 NodeId

// 1. Browse Object 子节点过滤 Method
var methods = ua.Browse("ns=2;s=Calculator", filter: NodeClass.Method);
foreach (var m in methods)
Console.WriteLine($" {m.BrowseName} -> {m.NodeId}");

// 2. 看入参 / 出参签名 (Browse 该方法节点的 Property)
var props = ua.Browse(methods[0].NodeId); // 含 InputArguments / OutputArguments

输入参数构造

按方法签名构造 Variant:

// Add(Int32, Int32) -> Int32
new Variant(3), new Variant(4)

// SetTemperature(string deviceId, double value)
new Variant("Boiler1"), new Variant(85.5)

// 带数组参数
new Variant(new[] { 1.0, 2.0, 3.0 })

// 复杂结构 (ExtensionObject) — 高级用法, 后续版本完善

异步 (后续版本)

当前 Call 是同步阻塞 (内部走 RPC + 等响应). 异步版本 (CallAsync) 在后续版本提供.

如果想异步, 用 Task.Run:

var result = await Task.Run(() => ua.Call(objId, mtdId, args));

下一步