tags:

views:

8245

answers:

19

I do not currently have this issue, but you never know, and thought experiments are always fun.

Ignoring the obvious problems that you would have to have with your architecture to even be attempting this, let's assume that you had some horribly-written code of someone else's design, and you needed to do a bunch of wide and varied operations in the same code block, e.g.:

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

Multiplied by a hundred. Some of these might work, others might go badly wrong. What you need is the C# equivalent of "on error resume next", otherwise you're going to end up copying and pasting try-catches around the many lines of code.

How would you attempt to tackle this problem?

+6  A: 

On Error Resume Next is a really bad idea in the C# world. Nor would adding the equivalent to On Error Resume Next actually help you. All it would do is leave you in a bad state which could cause more subtle errors, data loss and possibly data corruption.

But to give the questioner his due, you could add a global handler and check the TargetSite to see which method borked. Then you could at least know what line it borked on. The next part would be to try and figure out how to set the "next statement" the same way the debugger does it. Hopefully your stack won't have unwound at this point or you can re-create it, but it's certainly worth a shot. However, given this approach the code would have to run in Debug mode every time so that you would have your debug symbols included.

Orion Adrian
A: 

Unfortunately you are probably out of luck. On Error Resume Next is a legacy option that is generally heavily discouraged, and does not have an equivalent to my knowledge in C#.

I would recommend leaving the code in VB (It sounds like that was the source, given your specific request for OnError ResumeNext) and interfacing with or from a C# dll or exe that implements whatever new code you need. Then preform refactoring to cause the code to be safe, and convert this safe code to C# as you do this.

Guvante
+3  A: 

Rewrite the code. Try to find sets of statements which logically depend on each other, so that if one fails then the next ones make no sense, and hive them off into their own functions and put try-catches round them, if you want to ignore the result of that and continue.

Khoth
A: 

Hilite each line, one at a time, 'Surround with' try/catch. That avoids the copying pasting you mentioned

mattlant
This doesn't actually work. You'll break scoping.int i;i = 5;can't be try catch'ed.
Orion Adrian
What the hell are you talking about? Where in the heck was there any variable assignment in the posters question?
mattlant
The implication was that it was "times 100" meaning that there's a lot of code there that wasn't presented. In that case then there's bound to be a variable assignment or two along with the dozen or so other constructs that can't be try/catch'ed singly.
Orion Adrian
100 X those four lines of code still presents ZERO assignments.
mattlant
His code has a "e.g." We're both assuming what the rest of the code looks like. It could be all the same at which point it could be easily refactored into methods or you could be right and then the ATTEMPT() thing above could work.
Orion Adrian
Its all ABout context man. THIS POST was OBVIOUSLY not an attempt at aquiring the code guru uber pattern way of doing it. I think that was VERY clear! Maybe I am special because I could see that in the question. Maybe you are special because you can see beyond the code sample that was given. I dunno
mattlant
regardless I wont be back on this thread as its degenerated into nothingness.
mattlant
@mattlant I would give you +1 for funniest answer in this thread, but I am afraid that you are being serious :):):)
Marek
+17  A: 

Refactor into individual, well-named methods:

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

Each of those is protected appropriately.

plinth
+1  A: 

If you can get the compiler to give you an expression tree for this code, then you could modify that expression tree by replacing each statement with a new try-catch block that wraps the original statement. This isn't as far-fetched as it sounds; for LINQ, C# acquired the ability to capture lambda expressions as expression trees that can be manipulated in user code at runtime.

This approach is not possible today with .NET 3.5 -- if for no other reason than the lack of a "try" statement in System.Linq.Expressions. However, it may very well be viable in a future version of C# once the merge of the DLR and LINQ expression trees is complete.

Curt Hagenlocher
A: 

Ignoring all the reasons you'd want to avoid doing this.......

If it were simply a need to keep # of lines down, you could try something like:

int totalMethodCount = xxx;
for(int counter = 0; counter < totalMethodCount; counter++) {
    try {
     if (counter == 0) WidgetMaker.SetAlignment(57);
     if (counter == 1) contactForm["Title"] = txtTitle.Text;
     if (counter == 2) Casserole.Season(true, false);
     if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
    } catch (Exception ex) {
     // log here
    }
}

However, you'd have to keep an eye on variable scope if you try to reuse any of the results of the calls.

tyshock
+4  A: 

This is one of the things that having a preprocessor is useful for. You could define a macro that swallows exceptions, then with a quick script add that macro to all lines.

So, if this were C++, you could do something like this:

#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);

Unfortunately, not many languages seem to include a preprocessor like C/C++ did.

You could create your own preprocessor and add it as a pre-build step. If you felt like completely automating it you could probably write a preprocessor that would take the actual code file and add the try/catch stuff in on its own (so you don't have to add those ATTEMPT() blocks to the code manually). Making sure it only modified the lines it's supposed to could be difficult though (have to skip variable declarations, loop constructs, etc to that you don't break the build).

However, I think these are horrible ideas and should never be done, but the question was asked. :)

Really, you shouldn't ever do this. You need to find what's causing the error and fix it. Swallowing/ignoring errors is a bad thing to do, so I think the correct answer here is "Fix the bug, don't ignore it!". :)

Herms
Hey, someone who actually answers the question, you got my vote ;)
mattlant
The problem is this still wouldn't work as intended, at least not without some additional thinking.If you do this then it's almost garunteed you're going to move variables out of scope and break your build.
Orion Adrian
That's why I said you need to be careful to skip variable declarations, along with other things.
Herms
Even if you don't break your build, which would be hard, there's a ton of stuff to actually look for beyond just variable declarations and looping constructs. I know you're suggesting he actually go through with it (quite the contrary).
Orion Adrian
But that's just what makes trying to write a tool for this fun! (or incredibly painful). :)
Herms
A: 

You could look at integrating the Enterprise Library's Exception Handling component for one idea of how to handle unhandled exceptions.

If this is for ASP.Net applications, there is a function in the Global.asax called, "Application_Error" that gets called in most cases with catastrophic failure being the other case usually.

JB King
+1  A: 

You could use goto, but it's still messy.

I've actually wanted a sort of single statement try-catch for a while. It would be helpful in certain cases, like adding logging code or something that you don't want to interrupt the main program flow if it fails.

I suspect something could be done with some of the features associated with linq, but don't really have time to look into it at the moment. If you could just find a way to wrap a statement as an anonymous function, then use another one to call that within a try-catch block it would work... but not sure if that's possible just yet.

Telos
+7  A: 

Fail Fast

To elaborate, I guess I am questioning the question. If an exception is thrown, why would you want your code to simply continue as if nothing has happened? Either you expect exceptions in certain situations, in which case you write a try-catch block around that code and handle them, or there is an unexpected error, in which case you should prefer your application to abort, or retry, or fail. Not carry on like a wounded zombie moaning 'brains'.

Matt Howells
Wiki link "answers" are really not that helpful.. Why not try expanding on this?
Rob Cooper
+1  A: 

This may help you in identifing the pieces that have the most problems.

@ JB King Thanks for reminding me. The Logging application block has a Instrumentation Event that can be used to trace events, you can find more info on the MS Enterprise library docs.

Using (New InstEvent)
<series of statements> 
End Using

All of the steps in this using will be traced to a log file, and you can parse that out to see where the log breaks (ex is thrown) and id the high offenders.

Refactoring is really your best bet, but if you have a lot, this may help you pinpoint the worst offenders.

StingyJack
+9  A: 

I would say do nothing.

Yup thats right, do NOTHING.

You have clearly identified two things to me:

  1. You know the architecture is borked.
  2. There is a ton of this crap.

I say:

  • Do nothing.
  • Add a global error handler to send you an email every time it goes boom.
  • Wait until something falls over (or fails a test)
  • Correct that (Refactoring as necessary within the scope of the page).
  • Repeat every time a problem occurs.

You will have this cleared up in no time if it is that bad. Yeah I know it sounds sucky and you may be pulling your hair out with bugfixes to begin with, but it will allow you to fix the needy/buggy code before the (large) amount of code that may actually be working no matter how crappy it looks.

Once you start winning the war, you will have a better handle on the code (due to all your refactoring) you will have a better idea for a winning design for it..

Trying to wrap all of it in bubble wrap is probably going to take just a long to do and you will still not be any closer to fixing the problems.

Rob Cooper
+25  A: 
public delegate void VoidDelegate();

public static class Utils
{
  public static void Try(VoidDelegate v) {
    try {
      v();
    }
    catch {}
  }
}

Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );
Lost Plugin Writer
This makes the most sense, really.
Jon Limjap
As of .net 3.5, you can use Action instead of voidDelegate.
David B
I love this! This is like getting the @ operator from PHP in C#. http://www.php.net/manual/en/language.operators.errorcontrol.php And I don't have to write this question.
tyndall
How come Action works here also even if you start passing parameters? Is the compiler handling this for you... like ignoring or dropping the params?
tyndall
As David B said, Action would be better
consultutah
@B. Tyndall - the Action doesn't take the parameters; they are passed via a thing called a "closure"
Daniel Earwicker
The major problem here is the "catch {}" which will catch things that should never be caught, including low-level errors in the state of the CLR.
Daniel Earwicker
+2  A: 

It's pretty obvious that you'd write the code in VB.NET, which actually does have On Error Resume Next, and export it in a DLL to C#. Anything else is just being a glutton for punishment.

Mark Brackett
I do believe that this is a valid solution which solves the puzzle posed in the question, so I am accepting the answer!
tags2k
+3  A: 

As someone mentioned, VB allows this. How about doing it the same way in C#? Enter trusty reflector:

This:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

Translates into this:

public static void Main()
{
    // This item is obfuscated and can not be translated.
    int VB$ResumeTarget;
    try
    {
        int VB$CurrentStatement;
    Label_0001:
        ProjectData.ClearProjectError();
        int VB$ActiveHandler = -2;
    Label_0009:
        VB$CurrentStatement = 2;
        int i = 0;
    Label_000E:
        VB$CurrentStatement = 3;
        int y = (int) Math.Round((double) (5.0 / ((double) i)));
        goto Label_008F;
    Label_0029:
        VB$ResumeTarget = 0;
        switch ((VB$ResumeTarget + 1))
        {
            case 1:
                goto Label_0001;

            case 2:
                goto Label_0009;

            case 3:
                goto Label_000E;

            case 4:
                goto Label_008F;

            default:
                goto Label_0084;
        }
    Label_0049:
        VB$ResumeTarget = VB$CurrentStatement;
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
        {
            case 0:
                goto Label_0084;

            case 1:
                goto Label_0029;
        }
    }
    catch (object obj1) when (?)
    {
        ProjectData.SetProjectError((Exception) obj1);
        goto Label_0049;
    }
Label_0084:
    throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
    if (VB$ResumeTarget != 0)
    {
        ProjectData.ClearProjectError();
    }
}
Christopher
Very funny :):) Given the very nature of this question, I would recommend the original poster to implement this approach as soon as he faces the problem - it is the closest to his question. It is the same as the accepted answer (do it in VB and use on error resume next) and it is in C#. And I would also recommend him to face the rage of someone having to maintain this after him. It is about the mindset...you either want to try-catch every line of a thousand lines long method, or you refactor that method and make the whole thing better. No what-if thought experimeents needed.
Marek
+1  A: 

Why not use the reflection in c#? You could create a class that reflects on the code and use line #s as the hint for what to put in each individual try/catch block. This has a few advantages:

  1. Its slightly less ugly as it doesn't really you require mangle your source code and you can use it only during debug modes.
  2. You learn something interesting about c# while implementing it.

I however would recommend against any of this, unless of course you are taking over maintance of someelses work and you need to get a handle on the exceptions so you can fix them. Might be fun to write though.

Sam Hendley
fun is always good. Glad to see some more people's insite into this.
mattlant
A: 

Fun question; very terrible.

It'd be nice if you could use a macro. But this is blasted C#, so you might solve it with some preprocessor work or some external tool to wrap your lines in individual try-catch blocks. Not sure if you meant you didn't want to manually wrap them or that you wanted to avoid try-catch entirely.

Messing around with this, I tried labeling every line and jumping back from a single catch, without much luck. However, Christopher uncovered the correct way to do this. There's some interesting additional discussion of this at Dot Net Thoughts and at Mike Stall's .NET Blog.

EDIT: Of course. The try-catch / switch-goto solution listed won't actually compile since the try labels are out-of-scope in catch. Anyone know what's missing to make something like this compile?

You could automate this with a compiler preprocess step or maybe hack up Mike Stall's Inline IL tool to inject some error-ignorance.

(Orion Adrian's answer about examining the Exception and trying to set the next instruction is interesting too.)

All in all, it seems like an interesting and instructive exercise. Of course, you'd have to decide at what point the effort to simulate ON ERROR RESUME NEXT outweighs the effort to fix the code. :-)

bill weaver
A: 

This is funny. I was one of the few to actually answer within the context of the question. My answer helped avoid one of the key aspects of his question : Avoiding Copying and Pasting try/catch blocks. But i guess what i suggested for whatever reason doesnt help with that? Thanks all for downvoting an answer that actually was a VERY valid answer to a key aspect of the question.

The point of the voting is to self moderate relevancy/accuracy of questions/answers. Its not a vote about things you like or dislike, unless specifically asked that. Its like someone asking for help to solve a problem, and someone gives an option using C#, and he gets downvoted and people syaing, "C# is teh $hitzors, Java rulez". But if the question asked for a Java answer and someone posted a C# answer, then ya maybe that deserves a downvote as its not relevant.

Well, the answer i gave was very relevant, but got voted on by feeling and opinion. nice. I hope you all are not doing that to other valid Q&A's. ANd i dont care all that much for the rep points except the more I get the more it allows me to down vote answers that actually are not relevant, or incorrect.

mattlant