public override void on_data_available(DDS.DataReader reader)
            {
                try
                {
                    DDS.TypedDataReader <T> dataReader =
                        (DDS.TypedDataReader <T>)reader;

                    dataReader.take(
                        _dataSeq,
                        _infoSeq,
                        DDS.ResourceLimitsQosPolicy.LENGTH_UNLIMITED,
                        DDS.SampleStateKind.ANY_SAMPLE_STATE,
                        DDS.ViewStateKind.ANY_VIEW_STATE,
                        DDS.InstanceStateKind.ANY_INSTANCE_STATE);

                    int dataLength = _dataSeq.length;
                    for (var i = 0; i < dataLength; ++i)
                    {
                        DDS.SampleInfo info = _infoSeq.get_at(i);
                        if (info.valid_data)
                        {
                            var data = new T();
                            data.copy_from(_dataSeq.get_at(i));
                            var key = _keySelector(data);
                            DDSKeyedSubject <TKey, T> keyedSubject;

                            if (!_keyedSubDict.ContainsKey(key))
                            {
                                keyedSubject = new DDSKeyedSubject <TKey, T>(key, _scheduler);
                                _keyedSubDict.Add(key, keyedSubject);
                                _handleKeyDict.Add(info.instance_handle, key);
                                _observer.OnNext(keyedSubject);
                            }
                            else
                            {
                                keyedSubject = _keyedSubDict[key];
                                if (_externalSubDict)
                                {
                                    if (!_handleKeyDict.ContainsKey(info.instance_handle))
                                    {
                                        _handleKeyDict.Add(info.instance_handle, key);
                                        _observer.OnNext(keyedSubject);
                                    }
                                }
                            }

                            keyedSubject.OnNext(data);
                        }
                        else if (info.instance_state == DDS.InstanceStateKind.NOT_ALIVE_DISPOSED_INSTANCE_STATE)
                        {
                            if (_handleKeyDict.ContainsKey(info.instance_handle))
                            {
                                var key = _handleKeyDict[info.instance_handle];
                                if (_keyedSubDict.ContainsKey(key))
                                {
                                    var keyedSub = _keyedSubDict[key];
                                    _keyedSubDict.Remove(key);
                                    _handleKeyDict.Remove(info.instance_handle);
                                    keyedSub.OnCompleted();
                                    /* FIXME: If the instance comes alive again, it will break the Rx contract */
                                }
                                else
                                {
                                    Console.WriteLine(
                                        "InstanceDataReaderListener invariant broken: keyedSubDict does not contain key");
                                }
                            }
                            else
                            {
                                Console.WriteLine(
                                    "InstanceDataReaderListener invariant broken: handleKeyDict does not contain info.instance_handle");
                            }
                        }
                    }

                    dataReader.return_loan(_dataSeq, _infoSeq);
                }
                catch (DDS.Retcode_NoData)
                {
                }
                catch (DDS.Exception ex)
                {
                    _observer.OnError(ex);
                    Console.WriteLine("ObservableKeyedTopic: InstanceDataReaderListener: take error {0}", ex);
                }
            }
        private void ReceiveData()
        {
            DDS.ConditionSeq activeConditions = new DDS.ConditionSeq();
            while (true)
            {
                try
                {
                    _waitset.wait(activeConditions, _timeout);
                    for (var c = 0; c < activeConditions.length; ++c)
                    {
                        if (activeConditions.get_at(c) == _statusCondition)
                        {
                            DDS.StatusMask triggeredmask =
                                _reader.get_status_changes();

                            if ((triggeredmask &
                                 (DDS.StatusMask)
                                 DDS.StatusKind.DATA_AVAILABLE_STATUS) != 0)
                            {
                                try
                                {
                                    DDS.TypedDataReader <T> dataReader
                                        = (DDS.TypedDataReader <T>)_reader;

                                    dataReader.take(
                                        _dataSeq,
                                        _infoSeq,
                                        DDS.ResourceLimitsQosPolicy.LENGTH_UNLIMITED,
                                        DDS.SampleStateKind.ANY_SAMPLE_STATE,
                                        DDS.ViewStateKind.ANY_VIEW_STATE,
                                        DDS.InstanceStateKind.ANY_INSTANCE_STATE);

                                    int dataLength = _dataSeq.length;
                                    //Console.WriteLine("Received {0}", dataLength);
                                    for (var i = 0; i < dataLength; ++i)
                                    {
                                        DDS.SampleInfo info = _infoSeq.get_at(i);
                                        if (info.valid_data)
                                        {
                                            var data = new T();
                                            data.copy_from(_dataSeq.get_at(i));
                                            var key = _keySelector(data);
                                            DDSKeyedSubject <TKey, T> keyedSubject;

                                            if (!_keyedSubjectDict.ContainsKey(key))
                                            {
                                                keyedSubject = new DDSKeyedSubject <TKey, T>(key, _scheduler);
                                                _keyedSubjectDict.Add(key, keyedSubject);
                                                _handleKeyDict.Add(info.instance_handle, key);
                                                _groupSubject.OnNext(keyedSubject);
                                            }
                                            else
                                            {
                                                keyedSubject = _keyedSubjectDict[key];
                                                if (_externalSubDict)
                                                {
                                                    if (!_handleKeyDict.ContainsKey(info.instance_handle))
                                                    {
                                                        _handleKeyDict.Add(info.instance_handle, key);
                                                        _groupSubject.OnNext(keyedSubject);
                                                    }
                                                }
                                            }

                                            keyedSubject.OnNext(data);
                                        }
                                        else if (info.instance_state ==
                                                 DDS.InstanceStateKind.NOT_ALIVE_DISPOSED_INSTANCE_STATE)
                                        {
                                            if (_handleKeyDict.ContainsKey(info.instance_handle))
                                            {
                                                var key = _handleKeyDict[info.instance_handle];
                                                if (_keyedSubjectDict.ContainsKey(key))
                                                {
                                                    var keyedSub = _keyedSubjectDict[key];
                                                    _keyedSubjectDict.Remove(key);
                                                    _handleKeyDict.Remove(info.instance_handle);
                                                    keyedSub.OnCompleted();
                                                    /* FIXME: If the instance comes alive again, it will break the Rx contract */
                                                }
                                                else
                                                {
                                                    Console.WriteLine(
                                                        "InstanceDataReaderListener invariant broken: keyedSubDict does not contain key");
                                                }
                                            }
                                            else
                                            {
                                                Console.WriteLine(
                                                    "InstanceDataReaderListener invariant broken: handleKeyDict does not contain info.instance_handle");
                                            }
                                        }
                                    }

                                    dataReader.return_loan(_dataSeq, _infoSeq);
                                }
                                catch (DDS.Retcode_NoData)
                                {
                                    _subject.OnCompleted();
                                    return;
                                }
                                catch (Exception ex)
                                {
                                    _subject.OnError(ex);
                                    Console.WriteLine($"ObservableTopicWaitSet: take error {ex}");
                                }
                            }
                            else
                            {
                                StatusKindPrinter.print((int)triggeredmask);
                                if ((triggeredmask &
                                     (DDS.StatusMask)
                                     DDS.StatusKind.SUBSCRIPTION_MATCHED_STATUS) != 0)
                                {
                                    DDS.SubscriptionMatchedStatus status = new DDS.SubscriptionMatchedStatus();
                                    _reader.get_subscription_matched_status(ref status);
                                    Console.WriteLine($"Subscription matched. current_count = {status.current_count}");
                                }

                                if ((triggeredmask &
                                     (DDS.StatusMask)
                                     DDS.StatusKind.LIVELINESS_CHANGED_STATUS) != 0)
                                {
                                    DDS.LivelinessChangedStatus status = new DDS.LivelinessChangedStatus();
                                    _reader.get_liveliness_changed_status(ref status);
                                    Console.WriteLine($"Liveliness changed. alive_count = {status.alive_count}");
                                }

                                if ((triggeredmask &
                                     (DDS.StatusMask)
                                     DDS.StatusKind.SAMPLE_LOST_STATUS) != 0)
                                {
                                    DDS.SampleLostStatus status = new DDS.SampleLostStatus();
                                    _reader.get_sample_lost_status(ref status);
                                    Console.WriteLine($"Sample lost. Reason = {status.last_reason.ToString()}");
                                }

                                if ((triggeredmask &
                                     (DDS.StatusMask)
                                     DDS.StatusKind.SAMPLE_REJECTED_STATUS) != 0)
                                {
                                    DDS.SampleRejectedStatus status = new DDS.SampleRejectedStatus();
                                    _reader.get_sample_rejected_status(ref status);
                                    Console.WriteLine($"Sample Rejected. Reason = {status.last_reason.ToString()}");
                                }
                            }
                        }
                    }
                }
                catch (DDS.Retcode_Timeout)
                {
                    Console.WriteLine("wait timed out");
                }
            }
        }