跳到主要内容

Read / Write

前置阅读

Read

public DataValue Read(string nodeId, AttributeId attribute = AttributeId.Value);

读单节点的指定 Attribute.

参数类型默认说明
nodeIdstringNodeId 字符串 (i=2258 / ns=2;s=...)
attributeAttributeIdValue (13)要读的属性

返回: DataValue (实现 IDisposable, 必须用 using)

异常: OpcUaException (BadNodeIdUnknown / BadNotReadable / BadCommunicationError / ...)

// 读 Value
using var dv = ua.Read("ns=2;s=Temperature");
Console.WriteLine(dv.Value.AsDouble);

// 读 DisplayName
using var dn = ua.Read("ns=2;s=Temperature", AttributeId.DisplayName);
Console.WriteLine(dn.Value.AsString);

ReadMany

同 Attribute 批量

public IReadOnlyList<DataValue> ReadMany(
IReadOnlyList<string> nodeIds,
AttributeId attribute = AttributeId.Value);

一次 RPC 批量读多个节点的同一 Attribute.

var nodes = new[] { "ns=2;s=T1", "ns=2;s=T2", "ns=2;s=T3" };
var values = ua.ReadMany(nodes);
for (int i = 0; i < nodes.Length; i++)
Console.WriteLine($"{nodes[i]} = {values[i].Value}");

任意 NodeId + AttributeId 组合

public IReadOnlyList<DataValue> ReadMany(
IReadOnlyList<(string nodeId, AttributeId attr)> items);
var items = new (string, AttributeId)[]
{
("ns=2;s=T1", AttributeId.Value),
("ns=2;s=T1", AttributeId.DataType),
("ns=2;s=T2", AttributeId.Value),
};
var results = ua.ReadMany(items);

性能: 批量比循环单读快 ~N 倍 (省 N-1 次 RPC 往返).


Write

public StatusCode Write(string nodeId, Variant value, AttributeId attribute = AttributeId.Value);

写单节点.

StatusCode st = ua.Write("ns=2;s=Setpoint", new Variant(42.5));
if (st != StatusCode.Good) Console.WriteLine($"Write failed: {st}");

返回 StatusCode (Good / BadNotWritable / BadTypeMismatch / BadUserAccessDenied / ...).

业务级失败不抛异常

Write 不抛异常 (除非 transport 级错误), 业务级失败通过返回值判断. 必须检查返回值, 不要假定 Good.


Variant 构造速查

new Variant(true)            // Boolean
new Variant((short)42) // Int16
new Variant(42) // Int32
new Variant(42L) // Int64
new Variant(3.14) // Double
new Variant(3.14f) // Float
new Variant("hello") // String
new Variant(DateTime.UtcNow) // DateTime
new Variant(Guid.NewGuid()) // Guid
new Variant(new byte[]{...}) // ByteString

// 数组
new Variant(new[] { 1.0, 2.0, 3.0 })
new Variant(new[] { "a", "b", "c" })

详见 Variant 数据类型.


DataValue 字段速查

字段类型说明
ValueVariant实际值 (可能为 null)
StatusStatusCodeGood / Bad* / Uncertain*
SourceTimestampDateTime?数据源时间戳
ServerTimestampDateTime?服务端打的时间戳
using var dv = ua.Read("ns=2;s=T1");
if (dv.Status != StatusCode.Good)
{
Console.WriteLine($"Bad value: {dv.Status}");
return;
}
Console.WriteLine($"{dv.Value.AsDouble} @ {dv.SourceTimestamp}");

AttributeId 常用值

Id名称说明
1NodeId节点 ID
2NodeClass节点类别
3BrowseName浏览名
4DisplayName显示名
5Description描述
13Value变量值 (默认)
14DataType数据类型 NodeId
17AccessLevel访问权限位
20Historizing是否在记录历史
21ExecutableMethod 是否可执行

最佳实践

  • 批量优先: 监控 100+ Tag 用 ReadMany, 不要循环 Read (省 N-1 次 RPC)
  • 多 Attribute 也用批量: 大量读同一节点的不同 Attribute, 用 ReadMany((nodeId, attr)) 形式
  • 必须 Dispose: DataValue 实现 IDisposable, 漏 Dispose 会泄漏 native 内存
  • Write 检查返回值: 不要假定一定 Good
  • 实时变化用订阅: 不要 1 秒一次轮询 Read, 改用 Subscription DataChanged 事件 (服务端推送)

下一步