The following is a stripped down version of my code:
var obs = Observable.just(MessageResponse())
return obs.onErrorResumeNext(
// handle error
).doOnComplete {
// successfully completed
}
The observable is run from inside a flatMap (not shown). The onErrorResumeNext gets called yet it isn't clear why. If I replace it with a doOnError, no exception is generated and the code runs successfully. What could be causing the onErrorResumeNext to be called?
Related
I'm trying to send a GLib.Notification from my application and pass a string parameter.
The name of the action is action-show-chat-view, and it is registered in the activate () method of my main application class:
public class MyApplication : Gtk.Application {
protected override void activate () {
// ...
var show_chat_view_action = new GLib.SimpleAction ("action-show-chat-view", GLib.VariantType.STRING);
show_chat_view_action.activate.connect ((parameter) => {
debug ("beep boop");
debug (parameter.get_string ());
});
add_action (show_chat_view_action);
// ...
}
}
To send the notification, I do the following:
var notification = new GLib.Notification ("Hello, world");
var target = new GLib.Variant.string ("foobar");
notification.set_default_action_and_target_value ("app.action-show-chat-view", target);
app.send_notification (null, notification); // app is the instance of the MyApplication class above
The notification is sent correctly and appears as expected, however when the notification is clicked to activate the action, I receive the following error:
GLib-GIO-CRITICAL **: 13:04:37.169: g_simple_action_activate: assertion 'simple->parameter_type == NULL ? parameter == NULL : (parameter != NULL && g_variant_is_of_type (parameter, simple->parameter_type))' failed
Other things that I've tried:
If I replace GLib.VariantType.STRING with null, and pass null as the target value on the notification (and removing parameter.get_string ()), I see the "beep boop" console output so I know that everything is at least wired up correctly and calling the right methods.
I have also tried registering the action with the app. prefix as well, however I read somewhere in documentation that when added via the Application.add_action () this is implicit.
I tried creating an action group with the type string s but got the same error.
I've tried using other Variant types besides STRING
I tried adding the following check before sending the notification to see if the types align, and they did: app.get_action_parameter_type ("action-show-chat-view").equal (target.get_type ()). This failed if I used the app. prefix, however I think that's expected behavior since it's registered without the prefix?
I looked into Flatpak sandbox permissions (this part is all new to me), but since the notification is sent successfully, I don't think that's the problem.
This appears to have been a bug with xdg-desktop-portal-gtk: https://github.com/flatpak/xdg-desktop-portal-gtk/pull/359. Despite being fixed, it has not yet been included in a release.
Some related discussion on an issue logged with elementary/notifications: https://github.com/elementary/notifications/issues/153
I'm trying to catch my custom Error, but for some reason my catch statements where I name the error that I know is being thrown, it skips those, goes to the default catch, and then gives me a EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) when I try to do print("Unexpected error \(error)")
Here's some abbreviated code:
This is the error that I have declared in my file that houses the class that I'm calling the method on (the class is called CC8DB):
public enum CC8RSVPError: Error {
case noEventOnDate
case invalidRSVPValue
}
I have a method declared as:
public func rsvpForEvent(_ inEventDate:Date?, forUserID inUserID:String, withValue inRSVPValue:String) throws -> CC8RSVPStatus
In another class were I'm calling this method, I have this:
do {
let rsvpResponse = try self.cc8DB.rsvpForEvent(inRSVPDate, forUserID: String(inMessage.author.id.rawValue), withValue: inRSVPValue);
...(other code to do when this doesn't fail)...
} catch CC8RSVPError.invalidRSVPValue {
...(Report specific error to user)...
} catch CC8RSVPError.noEventOnDate {
...(Report specific error to user)...
} catch {
...(Report general error to user)...
print("Error doing RSVP: \(error)");
}
And finally, in the CC8DB.rsvpForEvent() method, I'm triggering an error that does this:
throw CC8RSVPError.invalidRSVPValue;
The germane part of this method is:
public func rsvpForEvent(_ inEventDate:Date?, forUserID inUserID:String, withValue inRSVPValue:String) throws -> CC8RSVPStatus
{
var retStatus = CC8RSVPStatus(eventDate: nil, previousRSVP: "", newRSVP: "");
var upperRSVPValue:String = inRSVPValue.uppercased();
if (["YES", "MAYBE", "NO"].contains(upperRSVPValue)) {
//...(Code to do things when the info is correct)...
} else {
throw CC8RSVPError.invalidRSVPValue;
}
return retStatus;
}
For my test case where I'm seeing this, the inRSVPValue is "bla", to test what happens when a user doesn't enter a valid status value.
What I'm seeing is that rather than going into the catch that's specific for the CC8RSVPError.invalidRSVPValue case, it's going down to the general catch. In addition, I'm getting the EXC_BAD_INSTRUCTION on the line where I try and print the error value.
I've stepped through it to verify that I am indeed hitting the throw line that I think I am, and I can see in the debugger that the value of error is CC8DB.CC8RSVPError.invalidRSVPValue, but even if I try to do po error from the lldb command, I get the same exception error.
Has anyone seen this or know what I could have done to make do-try-catch not work right?
You could assign a constant named error inside your catch statement and inside the catch block read the constant and figure out what to do with it.
do something like:
} catch let error {
switch error {
case CC8RSVPError.noEventOnDate:
// code
case CC8RSVPError.invalidRSVPValue:
// code
}
}
Ok, I figured it out. I realized that somewhere along the way, some build setting got set so that I was statically linking into the binary (this is a command-line tool, a bot for Discord to be specific).
I saw some warnings about some of the Swift runtime libs being found in both the binary and the XCode developer runtime area, and realized that it might be that the error object was being used both in my CC8DB module in the binary and in the built-modules folder (or something to that effect).
I need to statically link for when I actually deploy the bot to where it's going to run, so I must have turned something on that won't turn off (I deleted the extra flags that I thought turned that on, but that wasn't fixing it).
Basically, I recreated my .xcodeproj file with swift package generate-xcodeproj to clear out whatever I broke, and now it works as expected.
Thanks to everyone who looked at this and offered help (especially #gmogames for his time and help). I'm sure it helped lead me down the path of figuring this out.
Is there a hook in NUnit to execute code only when assertion fails without catching the exception itself. Basically, it should accept action delegate to be executed when assertion fails and then re-throw exception. Why do I need this?
I need to compare two objects and dump the result on the screen, for easier debugging, when assertion fails.
Something like this works but is a bad hack, The problem is that it eagerly evaluates ProcessCompareError so I have unnecessary overhead, plus it does it no matter if there is an error or not. So, is there overload that will accept the delegate that would be executed when assertion fails?
Assert.That(benefitLimitComparer.Compare(copyBenefitLimit, origBenefitLimit), Is.EqualTo(0),limitError, ProcessCompareError(origBenefitLimit, copyBenefitLimit));
}
}
}
private string ProcessCompareError(BenefitLimit origBenefitLimit, BenefitLimit copyBenefitLimit)
{
Console.WriteLine("Original: ");
ObjectDumper.Write(origBenefitLimit);
Console.WriteLine("Copy");
ObjectDumper.Write(copyBenefitLimit);
return "";
}
I'm not sure how it might be done through a delegate. One alternative is to store the result of the Compare. If the result is false, write out the contents of the objects and then call Assert.Fail()
There is a possibilty to wrap an assert as an Action in a try-catch. In the catch you can handle the additional compare:
public static void ExecuteAssert(Action assert)
{
if (assert == null) return;
try
{
assert();
}
catch (Exception ex)
{
// perform the compare
}
}
As remark: I use a similar method to continue test execution and avoid the entire test to stop, if some non-fatal checks fail. Actually I iterate through a number of actions:
private static void VerifyAll(params Action[] asserts)
using (IDbCommand command = new SqlCommand())
{
IDbDataAdapter adapter = new SqlDataAdapter();
DataSet ds = new DataSet();
adapter.SelectCommand = command;
command.Connection = _dataAccess.Connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "GetProcData";
command.Parameters.Add(new SqlParameter("#ProcID ", procId));
adapter.Fill(ds);
return ds.Tables[0].AsEnumerable();
}
This returns an IEnumerable DataRow The question is that since the return is within the using statement, will it property dispose of the IDBCommand? I know I can easily refactor this so I change the scope of the DataSet outside of the using, but it is more of a wonder than anything else.
Yes, this will work as expected with IDbCommand being properly disposed. The compiler will transform the using block to a try-catch-finally, where Dispose is invoked in the finally block.
Yes, the DB Command will be disposed, so far so good.
You can get troubles with IEnumerables. Because the items could potentially be produced when getting them from the IEnumerable, not when creating the IEnumerable, that is the nature of it. So it depends on how ds.Tables[0].AsEnumerable() is implemented. It could wait with executing the command until you get the first item. This is in the calling code, outside of the using block. You'll get an error, because the command had been disposed.
This is probably not an issue here, but should always be considered when returning IEnumerables (or lambda expressions) from a using block:
using (A a = new A())
{
return someItems.Select(x => a.Get(x));
}
When accessing the first item, a is already disposed and you get an error.
The IDbCommand is disposed correctly. As a rule of thumb when returning from within a using statement you are fine to do so so long as:
The thing you are returning isn't in the clause of the using
statement
The thing being returned isn't a reference created within the block of the using statement.
In the first case the using statement will dispose of the thing you are trying to return and in the second case the variable will go out of scope.
e.g.
//this is fine as result is createsd outside the scope of the block.
bool result = false;
using (SmtpClient mailClient = new SmtpClient())
{
try
{
mailClient.Send(...);
result = true;
}
catch(SmtpException)
{
result = false;
}
finally
{
return result;
}
}
Here, the using(){ ... } statement is our friend. When we exit the block our SmtpClient is disposed, and the result condition will still exist for you to use.
However, say we are writing a WinForm app or WPF app and we wrap a using block around our data context then we create a problem as the context disappears before the control can consume it.
// this will fail when you bind the customers to a form control!
using (DbContext context = new DBContext())
{
context.Customers.Where(c => c.Name.Contains("Bob")).Load();
return context.Customers.Local;
}
Here, the using(){ ... } statement hurts us. As when we come to dataBind our customer to a GridView (or other such databound control) the fact that we have disposed of the DbContext will mean our form has nothing to bind to so it will throw an exception!
HTH
The scope of your IDbCommand object is very clear: between the brackets { and }. As soon as your program flow exits from there, the object is disposed.
I have a WinFrom App, use synchronous method to download string from a url, and use Rx ToAsync Method to make it asynchronous and get the observable result, and when the result comes I show it on the Form.
Yesterday, I updated Rx to the latest release, and it was told that "Observable does not contain a definition of Context". I tried comment this line, the codes threw an exception that "Cross-thread operation not valid: Control 'tbx_Reference' accessed from a thread other than the thread it was created on."
I want to show the asynchronous result using Subscribe method. How can I fix this problem? thanks very much.
public static IObservable<TResult> DoWorkAsync(TParameter parameter,
Func<TParameter,TResult> actionSync)
{
Observable.Context = SynchronizationContext.Current;
Func<TParameter, IObservable<TResult>> ActionAsync = actionSync.ToAsync();
IObservable<TResult> results = from result in ActionAsync(parameter)
select result;
return results;
}
For your return statement, try:
return results.ObserveOnDispatcher();