Count of observers in a Rx Subject - system.reactive

With Rx, what is the best way to get the number of current observers in a Subject?
I have a scenario where I want to publish a message, but only if there are observers. If there are no observers, I need to do something else.
To get around this issue, what I've done is created my own ISubject implementation and expose a count of an internal IObserver collection. I'm sure there must be an out of the box way of doing this, I'm just not fully familiar with what Rx has to offer.
Thanks!

Use the Subject<T>.HasObservers property.
Source Code
I don't recall exactly when it was introduced, but I'm pretty sure that it wasn't always there. It was probably added in Rx 2.0.

You should avoid implementing your own observable (or subject) implementations whenever possible.
You could certainly try writing a wrapper class to help.
Try this:
public class Countable
{
private int _count;
public int Count { get { return _count; } }
public IObservable<T> GetCountable<T>(IObservable<T> source)
{
return Observable.Create<T>(o =>
{
Interlocked.Increment(ref _count);
var subscription = source.Subscribe(o);
var decrement = Disposable.Create(() =>
{
Interlocked.Decrement(ref _count);
});
return new CompositeDisposable(subscription, decrement);
});
}
}
You can then write code like this:
var xs = new Subject<int>();
var countable = new Countable();
var ys = countable.GetCountable(xs);
Console.WriteLine(countable.Count);
var s1 = ys.Subscribe(y => { });
Console.WriteLine(countable.Count);
var s2 = ys.Subscribe(y => { });
Console.WriteLine(countable.Count);
s1.Dispose();
Console.WriteLine(countable.Count);
s2.Dispose();
Console.WriteLine(countable.Count);
My results running this are:
0
1
2
1
0

use subject.observers.length, example:
import {Subject} from 'rxjs'
let subject = new Subject()
let s1 = subject.subscribe(v => console.log('observerA: ' + v))
subject.next(1) // observerA: 1
console.log(subject.observers.length) // 1
let s2 = subject.subscribe(v => {
console.log('observerB: ' + v)
if(v===3) s2.unsubscribe()
})
subject.next(2) // observerA: 2
console.log(subject.observers.length) // 2
subject.next(3) // observerA: 3
console.log(subject.observers.length) // 1

Related

ToObservable is not firing in some cases

RX is synchronous by default so we can confirm it
int j = 0;
Observable.Range(1, 2)
.SelectMany(i => {
return new[]{1}.ToObservable()
.Select(i1 => {
new[]{1}.ToObservable().Subscribe(i2 => j = 1);
return 0;
})
;
})
.Subscribe();
j.ShouldBe(1);
however in my code base I have a similar query that does not fire unless i use the Immediate scheduler.
public static IObservable<GitHubIssue> Save(this IObservable<IReadOnlyList<Issue>> source, IGitHubRepository repository){
var objectSpace = repository.ObjectSpace;
return source.SelectMany(list => list.ToObservable().Select(issue => {
var gitHubIssue = objectSpace.CreateObject<GitHubIssue>();
gitHubIssue.Id = issue.Id;
issue.Labels.ToObservable(Scheduler.Immediate).Select(label => {
var gitHubLabel =objectSpace.GetObjectsQuery<GitHubLabel>(true).FirstOrDefault(_ => label.Name == _.Name) ??
objectSpace.NewGitHubLabel(label);
gitHubIssue.Labels.Add(gitHubLabel);
return gitHubLabel;
}).Subscribe();
//previous selector is not executed
i fail to see the relation and why this happens
"RX is synchronous by default" - No, it is not. Each operator has its own default.
Take Observable.Range for example. Here's the implementation for when you don't provide a Scheduler:
public virtual IObservable<int> Range(int start, int count)
{
return Range_(start, count, SchedulerDefaults.Iteration);
}
Which in turn uses:
internal static IScheduler Iteration
{
get
{
return CurrentThreadScheduler.Instance;
}
}
If I take Observable.Timer as an counterpoint, I have this code:
public virtual IObservable<long> Timer(TimeSpan dueTime)
{
return Timer_(dueTime, SchedulerDefaults.TimeBasedOperations);
}
Which uses:
internal static IScheduler TimeBasedOperations
{
get
{
return DefaultScheduler.Instance;
}
}
The fact that you have to put in .ToObservable(Scheduler.Immediate) says you have an operator that doesn't use Scheduler.Immediate by default.
Now, ignoring all of this, what you should never ever do inside an observable pipeline is subscribe to another observable. Never ever. When you do this you are relying on side-effects and that's what's going wrong in your code.
You should always assume that any call to Subscribe runs sometime in the future, so even your assertion that j.ShouldBe(1) shouldn't ever be used after a Subscribe.
Your sample code should be more like this:
int j = 0;
Observable
.Range(1, 2)
.SelectMany(i =>
{
return
new[] { 1 }
.ToObservable()
.Select(i1 =>
{
return 1;
})
;
})
.Subscribe(x =>
{
j = x;
/* j only valid here */
});
/* j NOT valid here */
Rational concrete example of a side-effect:
int j = 0;
Observable
.Delay(Observable.Return(42), TimeSpan.FromSeconds(2.0))
.Do(x => j = x)
.Subscribe();
Console.WriteLine(j);
Ultimately j will be equal to 42, but not when Console.WriteLine(j) is called. Never rely on state outside of the observable that's updated within the observable.

MongoDB C# Combining Fields

The Plan:
So now what I basically want is to take my propertys out of the class, let the user pick some and then pull a List with ONLY those propertys out of MongoDB.
The Code:
here is where the method starts:
private void DoStuffExecute(object obj)
{
Class class= new Class();
ExtractClass(class);
if (propList != null)
{
var result = classService.DoStuff(propList);
}
}
in "ExtractClass()" the Propertys are being pulled out of the Class.
void ExtractClass(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
propList.Add(item.Name);
}
}
and finally in "classService.DoStuff()" i try to set the "fields".
public List<class> DoStuff(List<string> Props)
{
try
{
var filter = Builders<class>.Filter.Empty;
var fields = Builders<class>.Projection.Include(x => x.ID);
foreach (var item in Props)
{
string str = "x.";
str += item.ToString();
fields = Builders<class>.Projection.Include(x => str);
fields = Builders<class>.Projection.Include(x => item);
}
var result = MongoConnectionHandler.MongoCollection.Find(filter).Project<class>(fields).ToList();
return result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
var result = new List<class>();
return result;
}
}
when i run the programm it gives me an "Unable to determine the serialization information for x=> value"... since im giving it a string.
The Question:
Does anyone have an Idea how to repair the code above or even make the plan work in another way?
thank you.
First of all: you are using such code lines as : var filter = Builders<class>.Filter.Empty; It is not possible, because class is a reserved keyword in c# (https://msdn.microsoft.com/en-us/library/x53a06bb.aspx) I assume, it's your Model, and i will speak about it as about Model class.
Include Filter needs Expression as a parameter, not a string, you should construct is as a expression. That's the second thing. Third, you should combine your includes as a chain, So your part of creating Include Filter from string List should look like:
var filter = Builders<Model>.Filter.Empty;
var fields = Builders<Model>.Projection.Include(x => x.Id);
foreach (var item in Props)
{
var par = Expression.Parameter(typeof(Model));
var prop = Expression.Property(par, item);
var cast = Expression.Convert(prop, typeof(object));
var lambda = Expression.Lambda(cast, par);
fields = fields.Include((Expression<Func<Model, object>>)lambda);
}
I have all expresiions separate for better understanding: first you create Parameter (x=>), than you add property (x=>x.Property1), than you should cast it to object, and after all create Lambda Expression from it.
And now the last part: You don't need all of it, Include function could get jsut a string as a parameter. So you could instead of all expression call write this:
fields = fields.Include(item);

TYpescript : Static methods on Function as class

I have a fn that inherit an existing fn ( take Angular1 $q for example )
//$q original behavior
var defer = $q.defer();
defer.promise.then(function(result){})
//or
$q( (resolve, reject) => {
//promise execution here
}).then(function(result){});
If I want to decorate it, I would do :
var Qdecorator = function($delegate) {
var Q = function(resolver:any): any {
//do some extra stuff here
return $delegate.apply($delegate, arguments);
}
//Assign the static methods here:
Q.defer = function() {
//do some stuff
return $delegate.defer.apply($delegate, []);
}
//same goes for race, when, resole reject and so on
return Q;
}
Problem is that typescript complains about
Property defer, race, when, resolve, etc... does not exist on type '(resolver: any) => any'
I tried to use the IQService, and IPromise with no luck, btu I'd like to raise a more global question :
How do I define late static methods on function() that return an object without using new
I am copying pasting the answer to my question from this link:
https://www.typescriptlang.org/docs/handbook/interfaces.html
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

Autofac: Resolving contructor parameters based on single dependency

I have a scenario which I want autofac to resolve:
Here are my classes, I would have a factory method to take NetworkCredentials and return TopLevel object, this should internally resolve the InnerType1 and InnerType2 with the NetwokCredentials
public class TopLevel
{
public TopLevel(InnerType1 type1, InnerType2 type2)
{
}
}
public class InnerType1
{
public InnerType1(NetworkCredential credential)
{
}
}
public class InnerType2
{
public InnerType2(NetworkCredential credential)
{
}
}
Registration code > would something like this work ?
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => context.Resolve<TopLevel>(new TypedParameter(typeof(NetworkCredential), cred));
});
The crude approach could be to do resolve each contructor argument one by one inside resolution of TopLevel
No, that will not work since you are now instructing Autofac to provide a parameter value of type NetworkCredential to the TopLevel constructor which clearly requires two parameters of totally different types.
You will have to resolve InnerType1 and InnerType2 instances first and provide these to the TopLevel resolve. Something like this:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => {
var i1 = context.Resolve<InnerType1>(TypedParameter.From(cred));
var i2 = context.Resolve<InnerType2>(TypedParameter.From(cred));
return context.Resolve<TopLevel>(TypedParameter.From(i1), TypedParameter.From(i2));
};
});
Note: I'm not seeing the whole picture of your system here, but if you feel that this is crude, perhaps you should look at revising your class hierarchy. IMO there's a faint smell of "too complex" in your code here, you require two different classes to be configured with the same data which makes me want to de-duplicate :)
Similar to Peter's answer, but slightly different flavor:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var resolveInnerType1 = c.Resolve<Func<NetworkCredential, InnerType1>>();
var resolveInnerType2 = c.Resolve<Func<NetworkCredential, InnerType2>>();
var resolveTopLevel = c.Resolve<Func<InnerType1, InnerType2, TopLevel>>();
return (cred) => {
var i1 = resolveInnerType1(cred);
var i2 = resolveInnerType2(cred);
return resolveTopLevel(i1, i2);
};
});

CombineLatest, but only push for the left

I need to implement a version of CombineLatest (I'll call it WithLatest here) that calls the selector for every item on the left and the latest item on the right. It shouldn't push for items on the right changing only.
I think whether this is built Observable.Create or a combination of existing extensions is not particularly important; I'll be making this a "boxed" extension method either way.
Example
var left = new Subject<int>();
var right = new Subject<int>();
left.WithLatest(right, (l,r) => l + " " + r).Dump();
left.OnNext(1); // <1>
left.OnNext(2); // <2>
right.OnNext(1); // <3>
right.OnNext(2); // <4>
left.OnNext(3); // <5>
should yield
2 1
3 2
Edit: The logic of my example goes:
Left becomes populated with 1. Right is empty, no values pushed.
Left becomes updated with 2 (it forgets the previous value). Right is still empty, so nothing is pushed.
Right becomes populated with 1, so Left = 2 (the latest value), Right = 1 is pushed. Up to this point, there is no difference between WithLatest and CombineLatest
Right is updated -- nothing is pushed. This is what's different
Left is updated with 3, so Left = 3, Right = 2 (the latest value) is pushed.
It's been suggested that I try:
var lr = right.ObserveOn(Scheduler.TaskPool).Latest();
left.Select(l => l + " " + lr.First()).Dump();
but this blocks on the current thread for my test.
You can do this using existing operators.
Func<int, int, string> selector = (l, r) => l + " " + r;
var query = right.Publish(rs => left.Zip(rs.MostRecent(0), selector).SkipUntil(rs));
Publish ensures we only ever subscribe to right once and share the subscription among all subscribers to rs.
MostRecent turns an IObservable<T> into an IEnumerable<T> that always yields the most recently emitted value from the source observable.
Zip between IObservable<T> and IEnumerable<U> emits a value each time the observable emits a value.
SkipUntil skips the pairs (l, r) which occur before right ever emits a value.
I also had the same need for a CombineLatest which "pushes only for the left".
I made the solution an "overload" of Observable.Sample, because that's what the method does:
It samples a source (right) with a sampler (left), with the additional capability of providing a resultSelector (like in CombineLatest).
public static IObservable<TResult> Sample<TSource, TSample, TResult>(
this IObservable<TSource> source,
IObservable<TSample> sampler,
Func<TSource, TSample, TResult> resultSelector)
{
var multiSampler = sampler.Publish().RefCount();
return source.CombineLatest(multiSampler, resultSelector).Sample(multiSampler);
}
Based on the solution picked by the post author I think there's an even simpler solution utilizing DistinctUntilChanged:
public static IObservable<TResult> CombineLatestOnLeft<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource, IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector) {
return leftSource
.Select<TLeft, Tuple<TLeft, int>>(Tuple.Create<TLeft, int>)
.CombineLatest(rightSource,
(l, r) => new { Index = l.Item2, Left = l.Item1, Right = r })
.DistinctUntilChanged(x => x.Index)
.Select(x => selector(x.Left, x.Right));
}
or even
public static IObservable<TResult> CombineLatestOnLeft<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource, IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector) {
return leftSource
.CombineLatest(rightSource,
(l, r) => new { Left = l, Right = r })
.DistinctUntilChanged(x => x.Left)
.Select(x => selector(x.Left, x.Right));
}
if you only care about distinct values of leftSource
On latest System.Reactive, we can use WithLatestFrom extension method.
left.WithLatestFrom(right, (l, r) => l + " " + r).Dump();
The result would be below correctly.
3 2
Here's the hacky way using Create - didn't actually build it, mea culpa if it doesn't actually work :)
public static IObservable<TRet> WithLatest<TLeft, TRight, TRet>(
this IObservable<TLeft> lhs,
IObservable<TRight> rhs,
Func<TLeft, TRight, TRet> sel)
{
return Observable.Create<TRet>(subj => {
bool rhsSet = false;
bool deaded = false;
var latestRhs = default(TRight);
Action onDeaded = null;
var rhsDisp = rhs.Subscribe(
x => { latestRhs = x; rhsSet = true; },
ex => { subj.OnError(ex); onDeaded(); });
var lhsDisp = lhs
.Where(_ => deaded == false && rhsSet == true)
.Subscribe(
x => subj.OnNext(sel(x, latestRhs)),
ex => { subj.OnError(ex); onDeaded(); },
() => { subj.OnCompleted(); onDeaded(); });
onDeaded = () => {
deaded = true;
if (lhsDisp != null) {
lhsDisp.Dispose();
lhsDisp = null;
}
if (rhsDisp != null) {
rhsDisp.Dispose();
rhsDisp = null;
}
};
return onDeaded;
});
}
I made a RX operator for project today that does this.
Here's my solutions:
public static IObservable<Tuple<TSource, TTarget>> JoinLeftSoft<TSource, TTarget>(
this IObservable<TSource> source, IObservable<TTarget> right)
{
return source
.Select(x => new Tuple<object, TSource>(new object(), x))
.CombineLatest(right, (l, r) => new Tuple<object, TSource, TTarget>(l.Item1, l.Item2, r))
.DistinctUntilChanged(t => t.Item1)
.Select(t => new Tuple<TSource, TTarget>(t.Item2, t.Item3));
}