はこれでした解決すべき大きなチャレンジ! これが起こるような微妙な条件。 長い説明のために事前に謝罪しますが、私に負担してください!
TL; DR公開ソースに
サブスクリプションは、順に処理が、他のサブスクリプションの前に直接公開されていないソースにしています。キューをジャンプすることができます。 GroupJoin
サブスクリプション順は、ウィンドウの開閉を決定する際に重要です。
私が最初に懸念しているのは、主題を参照することです。 これはノーオペレーションでなければなりません。 Subject<T>
には購読料がありません。
ですから、Publish().RefCount()
を削除する場合:
var word = new Subject<string>();
var wordPub = word;//.Publish().RefCount();
var length = word.Select(i => i.Length);
を、あなたは同じ問題を取得します。
私はGroupJoin
を見ています(私の直感ではPublish().Refcount()
は赤ん坊です)。 私にとっては、これだけを目の当たりにすることは合理化するのが難しかったので、私は単純なデバッグにも頼りにしています。私は何十年も使っています - Trace
またはLog
拡張メソッド。
public interface ILogger
{
void Log(string input);
}
public class DumpLogger : ILogger
{
public void Log(string input)
{
//LinqPad `Dump()` extension method.
// Could use Console.Write instead.
input.Dump();
}
}
public static class ObservableLoggingExtensions
{
private static int _index = 0;
public static IObservable<T> Log<T>(this IObservable<T> source, ILogger logger, string name)
{
return Observable.Create<T>(o =>
{
var index = Interlocked.Increment(ref _index);
var label = $"{index:0000}{name}";
logger.Log($"{label}.Subscribe()");
var disposed = Disposable.Create(() => logger.Log($"{label}.Dispose()"));
var subscription = source
.Do(
x => logger.Log($"{label}.OnNext({x.ToString()})"),
ex => logger.Log($"{label}.OnError({ex})"),
() => logger.Log($"{label}.OnCompleted()")
)
.Subscribe(o);
return new CompositeDisposable(subscription, disposed);
});
}
}
私はそれがこのようになりますあなたの提供されたコードへのロギングを追加します。私のログに
var logger = new DumpLogger();
var word = new Subject<string>();
var wordPub = word.Publish().RefCount();
var length = word.Select(i => i.Length);
var report =
wordPub.Log(logger, "lhs")
.GroupJoin(word.Select(i => i.Length).Log(logger, "rhs"),
s => wordPub.Log(logger, "lhsDuration"),
s => Observable.Empty<int>().Log(logger, "rhsDuration"),
(w, a) => new { Word = w, Lengths = a })
.SelectMany(i => i.Lengths.Select(j => new { Word = i.Word, Length = j }));
report.Subscribe(i => ($"{i.Word} {i.Length}").Dump("OnNext"));
word.OnNext("Apple");
word.OnNext("Banana");
word.OnNext("Cat");
word.OnNext("Donkey");
word.OnNext("Elephant");
word.OnNext("Zebra");
これます、出力の公開では、次の
ログ(ようなもの)。 RefCount()が使用されました
0001lhs.Subscribe()
0002rhs.Subscribe()
0001lhs.OnNext(Apple)
0003lhsDuration.Subscribe()
0002rhs.OnNext(5)
0004rhsDuration.Subscribe()
0004rhsDuration.OnCompleted()
0004rhsDuration.Dispose()
OnNext
Apple 5
0001lhs.OnNext(Banana)
0005lhsDuration.Subscribe()
0003lhsDuration.OnNext(Banana)
0003lhsDuration.Dispose()
0002rhs.OnNext(6)
0006rhsDuration.Subscribe()
0006rhsDuration.OnCompleted()
0006rhsDuration.Dispose()
OnNext
Banana 6
...
私は、使用Publish().RefCount()
を削除し、次のように新しいログ出力は次のとおりです。我々は、ログに注釈を付ける起動したときにこれが私たちにいくつかの洞察力を与えるだけ件名
0001lhs.Subscribe()
0002rhs.Subscribe()
0001lhs.OnNext(Apple)
0003lhsDuration.Subscribe()
0002rhs.OnNext(5)
0004rhsDuration.Subscribe()
0004rhsDuration.OnCompleted()
0004rhsDuration.Dispose()
OnNext
Apple 5
0001lhs.OnNext(Banana)
0005lhsDuration.Subscribe()
0002rhs.OnNext(6)
0006rhsDuration.Subscribe()
0006rhsDuration.OnCompleted()
0006rhsDuration.Dispose()
OnNext
Apple 6
OnNext
Banana 6
0003lhsDuration.OnNext(Banana)
0003lhsDuration.Dispose()
...
なし
ログ、しかし問題は本当に明らかになったときでありますサブスクリプションの論理リストを使用します。私たちの注釈がword.OnNext("Banana");
が実行されたときに、この例では、オブザーバーのチェーンがこの順
にリンクされている。この
//word.Subsribers.Add(wordPub)
0001lhs.Subscribe() //wordPub.Subsribers.Add(0001lhs)
0002rhs.Subscribe() //word.Subsribers.Add(0002rhs)
0001lhs.OnNext(Apple)
0003lhsDuration.Subscribe() //wordPub.Subsribers.Add(0003lhsDuration)
0002rhs.OnNext(5)
0004rhsDuration.Subscribe()
0004rhsDuration.OnCompleted()
0004rhsDuration.Dispose()
OnNext
Apple 5
0001lhs.OnNext(Banana)
0005lhsDuration.Subscribe() //wordPub.Subsribers.Add(0005lhsDuration)
0003lhsDuration.OnNext(Banana)
0003lhsDuration.Dispose() //wordPub.Subsribers.Remove(0003lhsDuration)
0002rhs.OnNext(6)
0006rhsDuration.Subscribe()
0006rhsDuration.OnCompleted()
0006rhsDuration.Dispose()
OnNext
Banana 6
ように見えるかもしれませんRefCountプロパティを持つ元(作業)コードで
- wordPub
- 0002rhs
ただし、、wordPubには、サブスクリプションがあります! だから、本当の購読リストは
- wordPub
- 0001lhs
-
0003lhsDuration
- 0005lhsDuration
- 0002rhs
のように見えます我々は件名に注釈を付ける場合は210 のみword.OnNext("Banana");
はオブザーバーのチェーンが0003lhsDuration
ように、この順で
1. 0001lhs
2. 0002rhs
3. 0003lhsDuration
4. 0005lhsDuration
をリンクされて実行されたとき、我々は微妙この例では
0001lhs.Subscribe() //word.Subsribers.Add(0001lhs)
0002rhs.Subscribe() //word.Subsribers.Add(0002rhs)
0001lhs.OnNext(Apple)
0003lhsDuration.Subscribe() //word.Subsribers.Add(0003lhsDuration)
0002rhs.OnNext(5)
0004rhsDuration.Subscribe()
0004rhsDuration.OnCompleted()
0004rhsDuration.Dispose()
OnNext
Apple 5
0001lhs.OnNext(Banana)
0005lhsDuration.Subscribe() //word.Subsribers.Add(0005lhsDuration)
0002rhs.OnNext(6)
0006rhsDuration.Subscribe()
0006rhsDuration.OnCompleted()
0006rhsDuration.Dispose()
OnNext
Apple 6
OnNext
Banana 6
0003lhsDuration.OnNext(Banana)
0003lhsDuration.Dispose()
だから、どこにあるか見るログインサブスクリプションが0002rhs
の後にアクティブになると、rhsの値が送信され、まだ開いているウィンドウでそれを生成するまで、ウィンドウを終了する "バナナ"値は表示されません。
やれやれ
@ francezu13k50はあなたの問題を明らかにし、簡単な解決策はただword.Select(x => new { Word = x, Length = x.Length });
を使用することです指摘しているように、私はあなたが私は理解して私達にあなたの本当の問題を単純化したバージョン(感謝)を与えていると思うとなぜこれは適切ではないのですか? しかし、あなたの本当の問題空間が何であるか分からないので、現在のコードを持っていることを除いて、ソリューションを提供するために何を提案するべきか分かりません。
偉大な分析!私は自分のツールボックスにロガーを追加しています。実際の問題空間は、ビューモデルにrxを使用しています。電子メールアドレスのように、ユーザーがフォームに入力するプロパティがあります。電子メールアドレスが有効かどうかなど、これらのプロパティに関する計算があります。私は入力と出力を相関させようとしています。私は電子メールとisEmailValidに参加するかもしれません。相関関係のように見えるのは難しいです。たぶん私は出力に入力を含めるでしょう - isEmailValidは{Email = string、IsValid = bool}になるので、相関は必要ありません。 – JustinM
私がグループに参加している理由:私の実際の問題空間では、私はいくつかの遅い検証があります。 URLを検証するために、答えはnull(未知数)として開始されるので、UIを「計算中...」メッセージに続けてtrue/falseを更新して、UIを「良いURL」で更新することができます。または "bad URL!"と表示されます。 SelectManyを使用すると、UIに表示される検証メッセージを平坦化できます。だから実際にはかなり単純な問題であり、簡単な答えがないことが悲惨です。私の答えはPublish()に依存しています。RefCount()は不必要であると言います。 – JustinM
スキャンに関する私のソリューションを参照してください。私はこれがGroupJoinの予期せぬ/トリッキーさがなければ私が望むものを達成すると思う。繰り返しますが、私はここで本当に簡単なことをしようとしています - 入力と対応する出力を相関させます。これを拡張メソッドにして、簡単に再利用できるようにすることもできます。 – JustinM