Browse
Browse(string nodeId, NodeClass filter = Unspecified) — 列出指定节点的直接子节点 (一层).
前置阅读 / 配套
- 大节点分页请用 BrowseWithPaging + BrowseNext.
- 路径式批量解析请用 TranslateBrowsePaths.
签名
public IReadOnlyList<OpcUaReference> Browse(
string nodeId,
NodeClass filter = NodeClass.Unspecified);
public IReadOnlyList<IReadOnlyList<OpcUaReference>> BrowseMany(
IReadOnlyList<string> nodeIds,
NodeClass filter = NodeClass.Unspecified);
OpcUaReference 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| NodeId | string | 子节点 NodeId |
| BrowseName | string | 浏览名 (含 NamespaceIndex 前缀, 如 2:Temperature) |
| DisplayName | string | 显示名 |
| NodeClass | NodeClass | 子节点类别 |
例子
// 列出 Boiler1 下所有子节点
var children = ua.Browse("ns=2;s=Boiler1");
foreach (var c in children)
Console.WriteLine($" {c.NodeClass} {c.BrowseName} -> {c.NodeId}");
// 只看 Variable 类型
var vars = ua.Browse("ns=2;s=Boiler1", filter: NodeClass.Variable);
// 只看 Method
var methods = ua.Browse("ns=2;s=Calculator", filter: NodeClass.Method);
批量浏览 (BrowseMany)
如果同时要浏览多个节点 (例如 GUI 初次展开树), 用 BrowseMany 一次 RPC:
var roots = new[] { "i=85" /* Objects */, "i=86" /* Types */ };
var results = ua.BrowseMany(roots);
for (int i = 0; i < roots.Length; i++)
{
Console.WriteLine($"{roots[i]}:");
foreach (var c in results[i])
Console.WriteLine($" {c.BrowseName}");
}
如果某个节点浏览失败 (NodeId 错), 对应槽位返回空列表, 不抛异常.
NodeClass filter
| 值 | 包含 |
|---|---|
| Unspecified (0) | 全部 |
| Object (1) | 仅 Object |
| Variable (2) | 仅 Variable |
| Method (4) | 仅 Method |
| Object | Variable | 组合 (按位或) |
异常
OpcUaException(BadNodeIdUnknown) / OpcUaException(BadCommunicationError) 等. transport 失败抛, 单个子节点失败不抛.
大节点的分页 (ContinuationPoint)
如果一个节点有 1000+ 个子节点, 单次 Browse 服务端可能截断. 此时 Browse 只返回第一页.
要看全部, 用 BrowseWithPaging + BrowseNext:
var page = ua.BrowseWithPaging("ns=2;s=BigFolder");
var allRefs = new List<OpcUaReference>(page.References);
while (page.ContinuationPoint != null)
{
page = ua.BrowseNext(page.ContinuationPoint);
allRefs.AddRange(page.References);
}
性能
- 单次 Browse: ~5-15 ms (网络往返 + 服务端遍历)
- BrowseMany 批量: 总耗时 ~ 单次 (省 N-1 次往返)
- 1000+ 子节点会分页, 加 BrowseNext 处理
BrowseFiltered — 方向 + 引用类型过滤
BrowseFiltered 在 Browse 的基础上加 BrowseDirection + referenceTypeId + includeSubtypes + resultMask 过滤 (Part 4 §5.8.2.2 BrowseDescription).
public static IReadOnlyList<OpcUaReference> BrowseFiltered(
this DarraOpcUa session,
string nid,
NodeClass nodeClassFilter = NodeClass.Unspecified,
BrowseDirection direction = BrowseDirection.Forward,
string referenceTypeId = null,
bool includeSubtypes = true,
uint resultMask = 0x3F);
相关结构:
public enum BrowseDirection
{
Forward = 0, // 仅正向 (出引用), 父→子
Inverse = 1, // 仅反向 (入引用), 子→父
Both = 2 // 正反向都返回
}
示例
// 1) 仅看正向 + 仅 HierarchicalReferences (i=33)
var children = ua.BrowseFiltered("ns=2;s=Boiler1",
direction: BrowseDirection.Forward,
referenceTypeId: "i=33",
includeSubtypes: true);
// 2) 反向找父节点 (谁引用我)
var parents = ua.BrowseFiltered("ns=2;s=Tank.Level",
direction: BrowseDirection.Inverse);
foreach (var p in parents) Console.WriteLine($"父: {p.BrowseName}");
// 3) 双向 (Both) — 看节点全部连接关系
var all = ua.BrowseFiltered("ns=2;s=Robot.Joint1", direction: BrowseDirection.Both);
实现说明
- Stack 提供
DarraUa_Session_BrowseWithFilter时直调原生 - 否则 fallback 到现有
Browse+ 客户端按 NodeClass 过滤;referenceTypeId / direction / includeSubtypes在 fallback 模式下无法精确生效, 会打 Warning
BrowseAll — 自动续翻
public static IReadOnlyList<OpcUaReference> BrowseAll(
this DarraOpcUa session, string nodeId,
NodeClass filter = NodeClass.Unspecified, int maxPages = 32);
自动反复调 BrowseNext 直到 ContinuationPoint 为空, 不用业务侧手写循环。
var allRefs = ua.BrowseAll("ns=2;s=BigFolder");
Console.WriteLine($"共 {allRefs.Count} 个子节点");