C# RX-自定义IEqualityComparer出现明显错误

C# RX-自定义IEqualityComparer出现明显错误,c#,system.reactive,C#,System.reactive,我有一个基于轮询的协议,我想利用RX将其转换为基于推送的协议。每隔x秒,我使用协议请求标记(名称和值),然后从协议中获取它们 我只对更改标记中的值感兴趣,所以我使用DistinctUntilChanges函数 this.TagsChangeNotifier = _tags .Select(tag => { return Observable .Interval(ts) .Select(_ => { r

我有一个基于轮询的协议,我想利用RX将其转换为基于推送的协议。每隔x秒,我使用协议请求标记(名称和值),然后从协议中获取它们

我只对更改标记中的值感兴趣,所以我使用DistinctUntilChanges函数

this.TagsChangeNotifier = _tags
    .Select(tag => 
    { 
        return Observable
            .Interval(ts)
            .Select(_ => { return tag; })
            .DistinctUntilChanged(new DataTagComparer()); 
    })
    .Merge();
这是DataTagcomparer类

public class DataTagComparer : IEqualityComparer<DataTag>
{

    public bool Equals(DataTag x, DataTag y)
    {
            b = y.WeakRawValue.ToByteArray().SequenceEqual(x.WeakRawValue.ToByteArray());

        return b;
    }

    public int GetHashCode(DataTag obj)
    {
        return obj.Name.GetHashCode();
    }
}
等待10秒钟,从协议更改为返回2而不是1

Equals called: x = ("Test",1), y = ("Test",1)
Equals called: x = ("Test",2), y = ("Test",2)
Equals called: x = ("Test",2), y = ("Test",2)
Equals called: x = ("Test",2), y = ("Test",2)
等等

奇怪的是,它完全没有比较上一个值和当前值! 你知道有什么问题吗? 事实上,我正在处理这个糟糕的解决方案

public class DataTagComparer : IEqualityComparer<DataTag>
{

    private object val;

    public bool Equals(DataTag x, DataTag y)
    {
        bool b = true;

        if (val != null)
            b = val.ToByteArray().SequenceEqual(x.WeakRawValue.ToByteArray());

        val = x.WeakRawValue;

        return b;
    }

    public int GetHashCode(DataTag obj)
    {
        return obj.Name.GetHashCode();
    }
}
编辑:标签更新功能

this.timerHandle = Observable.Interval(ts).Select(_ => { Update(); return _; }).Publish().Connect();

根据你的描述,这…看起来不对-尽管我可能误解了你

this.TagsChangeNotifier = _tags
    // for each tag value in tags...
    .Select(tag => 
    { 
        // Tick off every TimeSpan ts, then...
        return Observable.Interval(ts)
            // Say we've "ticked"
            .Do(tick => Console.WriteLine("It's time to tick!"))
            // Return the value "tag" (which remains constant...)
            .Select(_ => { return tag; })
            // Say what we see
            .Do(t => Console.WriteLine("I see a {0}!", t))
            // But only when it's different from the last one
            // (but we never change the value?)
            .DistinctUntilChanged(new DataTagComparer()); 
    })    
    // And mash them all together into one stream
    .Merge();
我想这一切都取决于
\u tags
是什么,在某种程度上取决于
DataTag
的定义,但我认为这不是你真正想要的

编辑:

让我们画出流程-从
\u标记开始
,目前我假设它是一个
IObservable

Time   _tags
  |    tag1
  |    tag2
  |    tag3
到目前为止,一切都很好-现在,对于每一个,我们选择
并创建一个
间隔

Time   _tags
  |    tag1
  |     \---- Interval
  |
  |    tag2
  |     \---- Interval
  |
  |    tag3
  |     \---- Interval
  |
我们打勾一段时间,每次都重新选择标签:

Time   _tags
  |    tag1
  |     \---- Interval
  |            \-------Tick -> tag1
  |            \-------Tick -> tag1
  |            \-------Tick -> tag1
  |    tag2
  |     \---- Interval
  |            \-------Tick -> tag2
  |            \-------Tick -> tag2
  |            \-------Tick -> tag2
  |    tag3
  |     \---- Interval
  |            \-------Tick -> tag3
  |            \-------Tick -> tag3
  |            \-------Tick -> tag3
  |
然后我们添加
DistinctUntilChanged

Time   _tags
  |    tag1
  |     \---- Interval
  |            \-------Tick -> tag1 ---> tag1
  |            \-------Tick -> tag1 -X
  |            \-------Tick -> tag1 -X
  |    tag2
  |     \---- Interval
  |            \-------Tick -> tag2 ---> tag2
  |            \-------Tick -> tag2 -X
  |            \-------Tick -> tag2 -X
  |    tag3
  |     \---- Interval
  |            \-------Tick -> tag3 ---> tag3
  |            \-------Tick -> tag3 -X
  |            \-------Tick -> tag3 -X
  |
最后,我们合并子流:

Time   _tags                                      Output
  |    tag1                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag1 ---> tag1       tag1
  |            \-------Tick -> tag1 -X              |
  |            \-------Tick -> tag1 -X              |
  |    tag2                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag2 ---> tag2       tag2
  |            \-------Tick -> tag2 -X              |
  |            \-------Tick -> tag2 -X              |
  |    tag3                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag3 ---> tag3       tag3
  |            \-------Tick -> tag3 -X              |
  |            \-------Tick -> tag3 -X              |
  |
因此,如果您所需要做的只是在值流发生变化时捕获,您可以尝试以下形状:

// my fake source of "tags", in this case simple strings
var subject = new Subject<string>();
var source = subject.Publish().RefCount();

// Still want to track "distinct chains"
var distincts = source.DistinctUntilChanged();
// But we also want to "look into the future", and see the *next* distinct chain
var futureDistincts = source.DistinctUntilChanged().Skip(1);
// A "delta" occurs when a distinct chain ends, so we'll zip the two
// sequences together (since they are "now distinct" and "now + 1", this will mean changes)
var onlyDeltas = distincts
    .Zip(futureDistincts, (before,after) => Tuple.Create(before,after));

using(onlyDeltas.Subscribe(Console.WriteLine))
{
    subject.OnNext("Foo");
    subject.OnNext("Foo");
    subject.OnNext("Foo");
    subject.OnNext("Bar");  // BAM: triggers an output value of (Foo, Bar)
    subject.OnNext("Bar");
    subject.OnNext("Foo"); // BAM: triggers an output value of (Bar, Foo)
}
//我的假“标记”源代码,在本例中是简单字符串
var subject=新的subject();
var source=subject.Publish().RefCount();
//仍然希望跟踪“不同的链”
var distincts=source.DistinctUntilChanged();
//但我们也希望“展望未来”,看到“下一个”独特的链条
var futureDistincts=source.DistinctUntilChanged().Skip(1);
//当一条不同的链结束时,会出现一个“delta”,因此我们将压缩这两条链
//序列在一起(因为它们是“现在不同的”和“现在+1”,这意味着变化)
var onlyDeltas=distincts
.Zip(futureDistincts,(before,after)=>Tuple.Create(before,after));
使用(仅限于ltas.Subscribe(Console.WriteLine))
{
主题.OnNext(“Foo”);
主题.OnNext(“Foo”);
主题.OnNext(“Foo”);
subject.OnNext(“Bar”);//BAM:触发(Foo,Bar)的输出值
主题:OnNext(“律师”);
subject.OnNext(“Foo”);//BAM:触发(Bar,Foo)的输出值
}

数据标签的定义是什么?(或者你可以粘贴一个简化的版本,但仍然是这样)完成了,这是完整的版本。它们会改变,因为有另一个可观察的调用更新函数。请参见编辑部分中的代码。@Vincenzo Ok,但是当上面的
标记位于快照中时,
更新
如何影响它的值?你看到上面所说的内在创造的可观察的价值永远不会有变化的价值吗?我想我现在明白你的意思了。那么,为了实现我的目标,我应该改变代码中的哪些内容呢?@Vincenzo你只想捕捉流中的变化?是的,我想。我看到你的流程图,我同意。奇怪的是,更改标记值并没有将其推送到流中,因为比较函数在x和y上都获得新值
Time   _tags                                      Output
  |    tag1                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag1 ---> tag1       tag1
  |            \-------Tick -> tag1 -X              |
  |            \-------Tick -> tag1 -X              |
  |    tag2                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag2 ---> tag2       tag2
  |            \-------Tick -> tag2 -X              |
  |            \-------Tick -> tag2 -X              |
  |    tag3                                         |
  |     \---- Interval                              |
  |            \-------Tick -> tag3 ---> tag3       tag3
  |            \-------Tick -> tag3 -X              |
  |            \-------Tick -> tag3 -X              |
  |
// my fake source of "tags", in this case simple strings
var subject = new Subject<string>();
var source = subject.Publish().RefCount();

// Still want to track "distinct chains"
var distincts = source.DistinctUntilChanged();
// But we also want to "look into the future", and see the *next* distinct chain
var futureDistincts = source.DistinctUntilChanged().Skip(1);
// A "delta" occurs when a distinct chain ends, so we'll zip the two
// sequences together (since they are "now distinct" and "now + 1", this will mean changes)
var onlyDeltas = distincts
    .Zip(futureDistincts, (before,after) => Tuple.Create(before,after));

using(onlyDeltas.Subscribe(Console.WriteLine))
{
    subject.OnNext("Foo");
    subject.OnNext("Foo");
    subject.OnNext("Foo");
    subject.OnNext("Bar");  // BAM: triggers an output value of (Foo, Bar)
    subject.OnNext("Bar");
    subject.OnNext("Foo"); // BAM: triggers an output value of (Bar, Foo)
}