take the following as an example:
var ob = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(500).Replay(1).RefCount();
What I'm trying to achieve here is to obtain the value of the latest item in the sequence at any given time "synchronously". Which means extensions like FirstAsync can't make it up for me.
The StartWith and Replay bit ensures that there will always be a value, and the RefCount bit is necessary in my actual code to detect when I can do some disposal actions.
So to simulate this "any given time" part, let's try getting the latest value after 5 seconds:
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(x =>
{
// Try to get latest value from "ob" here.
});
So with a 5 second delay, I need to get the value 5 out of the sequence and these are what I have tried so far with no success:
ob.First() - returns 500
ob.Latest().Take(1) - same as above
ob.MostRecent(-1).First() - same as above
ob.MostRecent(-1) - gives me an IEnumerable<long> full of "500"
ob.Last() - never returns because it's waiting for the sequence to complete which it never will
ob.Latest().Last() - same as above
ob.ToTask().Result - same as above
ob.ToEnumerable() - same as above
ob.MostRecent().Last() same as above
It seems there's not much resources around that people can actually do this. The closest I can find is this: "Rx: operator for getting first and most recent value from an Observable stream", but it is not a synchronous call after all (still using a subscription) so it doesn't work for me.
Does any body know if this is actually doable?
To point out why your code probably isn't working as you expect it to
var ob = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(500).Replay(1).RefCount();
//Note at this point `ob` has never been subscribed to,
// so the Reference-count is 0 i.e. has not be connected.
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(x =>
{
// Try to get latest value from "ob" here.
//Here we make our first subscription to the `ob` sequence.
// This will connect the sequence (invoke subscribe)
// which will
// 1) invoke StartWith
// 2) invoke onNext(500)
// 3) invoke First()
// 4) First() will then unsubscribe() as it has the single value it needs
// 5) The refCount will now return to 0
// 6) The sequence will be unsubscribed to.
ob.First().Dump();
//Any future calls like `ob.First()` will thus always get the value 500.
});
Potentially what you want is
var ob = Observable.Interval(TimeSpan.FromSeconds(1))
.Publish(500);
var connection = ob.Connect();
//Note at this point `ob` has never been subscribed to, so the ReferenceCount is 0 i.e. has not be connected.
var subscription = Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(x =>
{
// Try to get latest value from "ob" here.
ob.First().Dump();
});
//Sometime later
subscription.Dispose();
connection.Dispose()
HOWEVER, You really don't want to be mixing Synchronous calls with Rx. You also generally don't want to be subscribing within a subscription (as .First() is a subscription). What you probably mean to be doing is getting the latest value, and stashing it somewhere. Using .First() is just a slippery slope. You probably would be better writing something like
var subscription = Observable.Timer(TimeSpan.FromSeconds(5))
.SelectMany(_=>ob.Take(1))
.Subscribe(x =>
{
//Do something with X here.
x.Dump();
});
You need to do something like this:
var ob = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(500);
var latestAndThenTheRest =
Observable
.Create<long>(o =>
{
var bs = new BehaviorSubject<long>(1);
var s1 = ob.Subscribe(bs);
var s2 = bs.Subscribe(o);
return new CompositeDisposable(s1, s2);
});
The only thing that you need to consider here is that ob must be a hot observable for this to even make sense. If it were cold then every subscriber would get a brand new subscription to the start of the ob sequence.
Just to clarify this a bit, and thanks for #LeeCampbell's answer.
What was not working:
var ob = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(500).Replay(1).RefCount();
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(x =>
{
ob.First().Dump();
// This gives you 500.
// Because this is the first time any one subscribes to the observable,
// so it starts right here and gives you the initial value.
});
What would actually work:
var ob = Observable.Interval(TimeSpan.FromSeconds(1)).StartWith(500).Replay(1).RefCount();
ob.Subscribe(); // Subscribe to start the above hot observable immediately.
Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(x =>
{
ob.First().Dump();
// This would give you either 3 or 4, depending on the speed and timing of your computer.
});
I'm not sure if this answer helps you, but have you looked into BehaviorSubject? It's an IObservable that remembers its latest value. It's a bit like a combination of a regular variable and an observable in one.
Otherwise, why don't you subscribe to 'ob' and store the latest value in a variable yourself?
Related
I have a method I verify as part of my test. One of its parameters is an array that can potentially be very large (over 100 bytes). How can I easily find the point of failure, without needing to go through some serious debugging?
The tested line is:
mockDependeny.verify(x=>x.callMethod(expectedModel, expectedModel.Length, It.IsAny<otherKindOfParam>()));
expectedModel is passed in the method (a theory) and is an array.
One set of data/expected in the theory works, but the next one says that it failed. The message it gives me is not very helpful -
Expected invocation on the mock at least once, but was never performed: x=>x.callMethod([1,2,3,4,5,6,7,8,9,10,...], 175 , It.IsAny())
Perfomed invocations:
Mock(x): MyDependency.callMethod([1,2,3,4,5,6,7,8,9,10,...], 175 , instanceOfOtherParam)
All I can glean from this is that somewhere in the next n-10 items in the array, there is something that does not match up ( the first ten items are the same, the overall length is the same)
Is there a way to get better feedback from the test, so I do not have to debug and manually compare the contents of the expceted vs actual arrays?
Replace the expectedModel array parameter with an It.Is<> and implement anything you want. E.g.:
mockDependency.Verify(x => x.callMethod(It.Is<byte[]>(m => VerifyThisEnumerableParam(m, expectedModel)), expectedModel.Length, It.IsAny<object>()));
...
private bool VerifyThisEnumerableParam<T>(IEnumerable<T> received, IEnumerable<T> expected)
{
if (received != expected)
{
var receivedArray = received.ToArray();
var expectedArray = expected.ToArray();
if (receivedArray.Length != expectedArray.Length ||
receivedArray.Where((t, idx) => !Object.Equals(t, expectedArray[idx])).Any())
{
// now let's visualize the two thing
throw new AssertFailedException($#"received != expected
expected: {String.Join(", ", expected.Select(t=>t.ToString()))}
received: {String.Join(", ", received.Select(t => t.ToString()))}");
}
}
return true;
}
The above isn't fool proof (no additional null, etc. checks), but hope you got the idea. If you prefer just the first differing index or something else just implement it in the method.
I am Calling API to get a list of contacts(they might be in 100's or 1000's) and list only lists 100 at a time and its giving me this pagination option with an object at the end of the list called 'nextpage' and with URL to next 100 and so on..
so in my c# code and am getting first 100 and looping through them (to do something) and looking up for 'nextpage' object and getting the URL and re-calling the API etc.. looks like this next page chain goes on depending on how many ever contacts we have.
can you please let me know if there is a way for me to loop through same code and still be able to use new URL from 'nextpage' object and run the logic for every 100 i get ?
Pseudo-code, as we have no concrete examples to work with, but...
Most APIs with pagination will have a total count of items. You can set a max items per iteration and track it like that, or check for the null next_object, depending on how the API handles it.
List<ApiObject> GetObjects() {
const int ITERATION_COUNT = 100;
int objectsCount = GetAPICount();
var ApiObjects = new List<ApiObject>();
for (int i = 0; i < objectsCount; i+= ITERATION_COUNT) {
// get the next 100
var apiObjects = callToAPI(i, ITERATION_COUNT); // pass the current offset, request the max per call
ApiObjects.AddRange(apiObjects);
} // this loop will stop after you've reached objectsCount, so you should have all
return ApiObjects;
}
// alternatively:
List<ApiObject> GetObjects() {
var nextObject = null;
var ApiObjects = new List<ApiObject>();
// get the first batch
var apiObjects = callToAPI(null);
ApiObjects.AddRange(apiObjects);
nextObject = callResponse.nextObject;
// and continue to loop until there's none left
while (nextObject != null) {
var apiObjects = callToAPI(null);
ApiObjects.AddRange(apiObjects);
nextObject = callResponse.nextObject;
}
return apiObjects;
}
That's the basic idea anyway, per the two usual web service approaches (with lots of detail left out, as this is not working code but only meant to demonstrate the general approach).
I love LINQ statements for the expressive syntax and other convenient features. However, I find it very troublesome to debug them sometimes. Specifically, when I run a LINQ statement on a collection and one of the elements in the collection causes an exception, how can I figure out what the problem input was and where the problem came from?
Imagine I have a text file with 1000 real numbers:
0.46578
12.314213
1.444876
...
I am reading this as a List<string> and loading it into a more specific data structure:
var file_contents = File.ReadAllLines("myfile.txt");
var data = file_contents.Select(s => double.Parse(s));
Now, for this particular input, I didn't bother to look at it carefully and it turns out the 876th line contains (line numbers shown):
875 5.56786450
876 Error: Could not calculate value.
878 0.0316213
For whatever reason (perhaps the file was generated by a script that malfunctioned). My LINQ method chain will of course throw an exception. The problem is, how do I figure which element of the list caused the exception, and what its value was?
To clarify, if instead I used a for-loop:
var data = new List<double>();
foreach(var row in file_contents)
{
var d = double.Parse(row);
data.Add(d);
}
Then the exception would highlight the string which calls double.Parse, and I would be able to mouse over row to easily see what the problem input was.
I can, of course, use Resharper to convert my LINQ statements into for-loops, and then debug them, but is there a better way?
Put a conditional breakpoint on the lambda function, where the condition is s.StartsWith("5.56"). You just need to have your cursor on the lambda and press F9. Assuming you're using visual studio.
var data = file_contents.Select(s => {
try
{
return double.Parse(s);
}
catch
{
throw; //breakpoint?
}
});
Disclaimer: I work for OzCode
LINQ debugging is hard borderline impossible using Visual Studio. I suggest you try using OzCode.
This is what your code looks when debugging (the exception in on the 6th item).
You can tell which item caused the exception by investigating the items that where passed to the Select clause - and since the last one triggered the exception - it's easy to find the offending value.
If you're interested you can try OzCode's LINQ debugging - we've just started an EAP
I would just use a tryparse personally.
var data = new List<string>
{
"0.46578",
"12.314213",
"Error: Could not calculate value.",
"1.444876",
};
double d;
var good = data.Where(s => Double.TryParse(s, out d)).Select(Double.Parse);
var bad = data.Where(s => !Double.TryParse(s, out d)).Select(x => new
{
key = data.IndexOf(x),
value = x
}).ToDictionary(x => x.key, x => x.value);
textBox1.AppendTextAddNewLine("Good Data:");
WriteDataToTextBox(good);
textBox1.AppendTextAddNewLine(String.Format("{0}{0}Bad Data:", Environment.NewLine));
WriteDataToTextBox(bad);
The AppendTextAddNewLine is simply an extension method I wrote for my little proof of concept test program
public static void AppendTextAddNewLine(this TextBox textBox, string textToAppend)
{
textBox.AppendText(textToAppend + Environment.NewLine);
}
Edit
The WriteDataToTextbox is a generic method that writes an IEnumerble<T> out to the text box.
void WriteDataToTextBox<T>(IEnumerable<T> data )
{
foreach (var row in data)
{
textBox1.AppendTextAddNewLine(row.ToString());
}
}
Forgot to put the output here so I figure I should do that. It shows the index of the bad data and the data itself that caused the problem.
Good Data:
0.46578
12.314213
1.444876
Bad Data:
[2, Error: Could not calculate value.]
I'm not sure why you don't like foreach loop here. LINQ uses it internally anyway, and as you've already realized there are some pros and cons of using LINQ and debugging is one of cons.
I would probably mix LINQ with foreach and end up with following:
// read all lines from file //
var file_contents = File.ReadAllLines("myfile.txt");
// set initial data list length to number of lines for better performance
var data = new List<double>(file_contents.Length);
// list for incorrect line numbers
var incorrectRows = new List<int>();
foreach (var x in file_contents.Select((s, i) => new {s, i}))
{
// x.s - line string
// x.i - line number
double value;
if (double.TryParse(x.s, out value))
data.Add(value); // add value, which was OK
else
incorrectRows.Add(x.i); // add index of incorrect value
}
That will prevent an exception at all and will give you line numbers for all incorrect values. It also iterate over file_contents just once and every value is being parsed only once.
Trying to understand how the Subject<T>, ReplaySubject<T> and other work. Here is example:
(Subject is Observable and observer)
public IObservable<int> CreateObservable()
{
Subject<int> subj = new Subject<int>(); // case 1
ReplaySubject<int> subj = new ReplaySubject<int>(); // case 2
Random rnd = new Random();
int maxValue = rnd.Next(20);
Trace.TraceInformation("Max value is: " + maxValue.ToString());
subj.OnNext(-1); // specific value
for(int iCounter = 0; iCounter < maxValue; iCounter++)
{
Trace.TraceInformation("Value: " + iCounter.ToString() + " is about to publish");
subj.OnNext(iCounter);
}
Trace.TraceInformation("Publish complete");
subj.OnComplete();
return subj;
}
public void Main()
{
//
// First subscription
CreateObservable()
.Subscribe(
onNext: (x)=>{
Trace.TraceInformation("X is: " + x.ToString());
});
//
// Second subscribe
CreateObservable()
.Subscribe(
onNext: (x2)=>{
Trace.TraceInformation("X2 is: " + x.ToString());
});
Case 1: The strange situation is - when I use Subject<T> no subscription is made (???) - I never see the "X is: " text - I only see the "Value is: " and "Max value is"... Why does Subject<T> does not push values to subscription ?
Case 2: If I use ReplaySubject<T> - I do see the values in Subscription but I could not apply Defer option to anything. Not to Subject and not to Observable.... So every subscription will receive different values because CreateObservable function is cold observable. Where is Defer ?
Whenever you need to create an observable out of thin air, Observable.Create should be the first thing to think of. Subjects enter the picture in two cases:
You need some kind of "addressable endpoint" to feed data to in order for all subscribers to receive it. Compare this to a .NET event which has both an invocation side (through delegate invocation) and a subscription side (through delegate combine with +- and -= syntax). You'll find in a lot of cases, you can achieve the same effect using Observable.Create.
You need multicasting of messages in a query pipeline, effectively sharing an observable sequence by many forks in your query logic, without triggering multiple subscriptions. (Think of subscribing to your favorite magazine once for your dorm and putting a photo copier right behind the letter box. You still pay one subscription, though all of your friends can read the magazine delivered through OnNext on the letter box.)
Also, in a lot of cases, there's already a built-in primitive in Rx that does exactly what you need. For example, there's From* factory methods to bridge with existing concepts (such as events, tasks, asynchronous methods, enumerable sequence), some of which using a subject under the covers. For the second case of multicasting logic, there's the Publish, Replay, etc. family of operators.
You need to be mindful of when code is executed.
In "Case 1", when you use a Subject<T>, you'll notice that the all of the calls to OnNext & OnCompleted finish before the observable is returned by the CreateObservable method. Since you are using a Subject<T> this means that any subsequent subscription will have missed all of the values so you should expect to get what you got - nothing.
You have to delay the operations on the subject until you have the observer subscribed. To do that using the Create method. Here's how:
public IObservable<int> CreateObservable()
{
return Observable.Create<int>(o =>
{
var subj = new Subject<int>();
var disposable = subj.Subscribe(o);
var rnd = new Random();
var maxValue = rnd.Next(20);
subj.OnNext(-1);
for(int iCounter = 0; iCounter < maxValue; iCounter++)
{
subj.OnNext(iCounter);
}
subj.OnCompleted();
return disposable;
});
}
I've removed all the trace code for succinctness.
So now, for every subscriber, you get a new execution of the code inside the Create method and you would now get the values from the internal Subject<T>.
The use of the Create method is generally the correct way to create observables that you return from methods.
Alternatively you could use a ReplaySubject<T> and avoid the use of the Create method. However this is unattractive for a number of reasons. It forces the computation of the entire sequence at creation time. This give you a cold observable that you could have produced more efficiently without using a replay subject.
Now, as an aside, you should try to avoid using subjects at all. The general rule is that if you're using a subject then you're doing something wrong. The CreateObservable method would be better written as this:
public IObservable<int> CreateObservable()
{
return Observable.Create<int>(o =>
{
var rnd = new Random();
var maxValue = rnd.Next(20);
return Observable.Range(-1, maxValue + 1).Subscribe(o);
});
}
No need for a subject at all.
Let me know if this helps.
I am looking for an extension such as Switch, but instead of defaulting to the most recent stream, I need a switch with an extra variable that can go back and forth based on another external event.
eg. We have observable which is a merger of 2 streams A and B, when event C is detected, I want observable A to pass through, and streams from B be ignored (lost). When event D is detected, I want observable A stream to be dropped and B be passed through.
What is the best linq operator for this? I suppose I could use a combination of where and some custom solution but really looking for a more elegant solution.
Also I would like to avoid subscribing/resubsribing from the stream where possible. I just find subscribing/resubscribing generally really hard to keep track of, plus hard to chain the operators.
There are many ways one can tackle this, let's look at a simple one. In this example I assume that events A and B are of the same type. I also assume that events C (tied to A) and D (tied to D) are also observables without any important information.
var streamA = new Subject<string>();
var streamB = new Subject<string>();
var switchToA = new Subject<Unit>();
var switchToB = new Subject<Unit>();
Now here we open a streamA window whenever switchToA fires and close it when switchToB fires, and do the opposite for streamB, then merge them:
public IObservable<string> SwitchingWindows(IObservable<string> streamA, IObservable<string> streamB, IObservable<Unit> switchToA, IObservable<Unit> switchToB)
{
var switchedA = streamA.Window(switchToA, _ => switchToB).Concat();
var switchedB = streamB.Window(switchToB, _ => switchToA).Concat();
return switchedA.Merge(switchedB);
}
Subscribe:
var all = SwitchingWindows(streamA, streamB, switchToA, switchToB);
all.Subscribe(x => Console.WriteLine(x));
Test:
streamA.OnNext("a1"); // skip
switchToA.OnNext(Unit.Default); // switch A
streamA.OnNext("a2"); // shown
streamB.OnNext("b1"); // skip
streamA.OnNext("a3"); // shown
switchToB.OnNext(Unit.Default); // switch B
streamB.OnNext("b2"); // shown
streamB.OnNext("b3"); // shown
streamA.OnNext("a4"); // skip
switchToA.OnNext(Unit.Default); // switch A
streamA.OnNext("a5"); // shown
streamB.OnNext("b4"); // skip
streamB.OnNext("b5"); // skip
switchToB.OnNext(Unit.Default); // switch B
streamB.OnNext("b6"); // shown
streamA.OnNext("a6"); // skip
Output is as expected:
a2
a3
b2
b3
a5
b6
The final stream all is 100% clean.