Call
签名
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));