You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Twincat Ads Reactive中Handle起始值为2是否为预期行为?

关于TwincatAds.Reactive中ValueNotification.Handle起始值的疑问

我在.NET 6 WPF桌面应用中使用TwincatAds.Reactive 6.0.190,同时采用MVVM模式,目标是实现一个监控PLC变量变化的类,将变量收集到字典后供ViewModel使用。

我的绑定通知及处理代码如下:

public void AttachNotification(IEnumerable<(string key, Type type)> Symbols)
{
    _observerValueNotification = Observer.Create<ValueNotification>(val =>
    {
        // Does handle really start from 2?
        var handle = val.Handle;
        if (val.UserData is object[] objects)
        {
            string tag = objects[handle - 2].ToString();

            if (!_values.Any(x => x.Key == tag))
                _values.Add(new SymbolModel { Key = tag, Value = val.Value });
            else
            {
                var symbol = _values.First(x => x.Key == tag);
                symbol.Value = val.Value;
            }
        }

        ValuesChanged?.Invoke(_values);
    });

    if (_plcWrapper.AdsClient != null)
    {
        // Get Symbols from SymbolLoader
        List<AnySymbolSpecifier> list = new();
        List<string> userData = new();
        foreach (var (key, type) in Symbols)
        {
            list.Add(new AnySymbolSpecifier(key, new AnyTypeSpecifier(type)));
            userData.Add(key);
        }
        _subscription2 = _plcWrapper.AdsClient.WhenNotificationEx(list, NotificationSettings.ImmediatelyOnChange, userData.ToArray())
                                              .Subscribe(_observerValueNotification);
    }
}

我使用ValueNotification是为了兼容结构体这类复杂PLC变量,通过WhenNotificationEx传入的UserData[]来标识变化的变量,原本打算用ValueNotification.Handle作为UserData[]的索引定位变量,但发现Handle的值从2开始。想确认:

  • 这是预期行为吗?
  • Handle的值是否始终从2开始?

回答

  1. Handle起始值为2是预期行为
    TwincatAds.Reactive底层基于倍福原生ADS库实现,Handle对应ADS通知句柄。原生ADS库会预留部分句柄用于系统级操作(比如句柄1可能对应默认内部通知),因此用户创建的自定义通知句柄会从2开始分配。

  2. Handle的值并非始终固定从2开始
    当前测试中Handle从2开始,但这个起始值不具备绝对固定性:

    • 若同一客户端实例下已创建过其他ADS通知,句柄会按递增顺序分配,新通知的Handle会从之前的最大句柄+1开始;
    • 若之前的通知被取消订阅并释放句柄,ADS库可能复用空闲句柄,导致新句柄的起始值不固定。

更可靠的变量关联方案

直接依赖Handle作为UserData数组索引存在风险,推荐两种稳定方案:

  • 将变量标识单独存入UserData:创建AnySymbolSpecifier时,把对应的tag作为单个UserData传入,回调中直接从val.UserData获取tag,无需依赖Handle索引;
  • 用字典映射Handle与tag:订阅前单独创建每个通知并记录Handle与tag的映射关系,后续通过字典快速查找。

方案1代码示例

foreach (var (key, type) in Symbols)
{
    list.Add(new AnySymbolSpecifier(key, new AnyTypeSpecifier(type)));
    // 每个符号对应单独的UserData(即tag)
    userData.Add(key);
}

// 回调中直接获取tag
if (val.UserData is string tag)
{
    if (!_values.Any(x => x.Key == tag))
        _values.Add(new SymbolModel { Key = tag, Value = val.Value });
    else
    {
        var symbol = _values.First(x => x.Key == tag);
        symbol.Value = val.Value;
    }
}

方案2代码示例

Dictionary<int, string> handleToTagMap = new();
List<IDisposable> subscriptions = new();

foreach (var (key, type) in Symbols)
{
    var specifier = new AnySymbolSpecifier(key, new AnyTypeSpecifier(type));
    var notification = _plcWrapper.AdsClient.WhenNotificationEx(specifier, NotificationSettings.ImmediatelyOnChange, key);
    var handle = notification.Subscribe(val =>
    {
        if (val.UserData is string tag)
        {
            // 处理变量更新逻辑
            if (!_values.Any(x => x.Key == tag))
                _values.Add(new SymbolModel { Key = tag, Value = val.Value });
            else
            {
                var symbol = _values.First(x => x.Key == tag);
                symbol.Value = val.Value;
            }
            ValuesChanged?.Invoke(_values);
        }
    });
    // 记录Handle与tag的映射
    handleToTagMap.Add(notification.Handle, key);
    subscriptions.Add(notification);
}

内容的提问来源于stack exchange,提问作者MIHOW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:25:22