Telling when a method has finished

  • Thread starter Thread starter Joshua Frank
  • Start date Start date
J

Joshua Frank

Hi All,

Is there any way to tell when the method you're in has exited? This
would be handy for things like:

Sub LongProcess()
'code
'code
ShowHourglass()

'long job...
'...
If IntermediateResultFails
'clean up
HideHourglass
Exit Sub
End If

'long job...
If IntermediateResultFails
'clean up
HideHourglass
Exit Sub
End If


HideHourglass
Exit Sub

In other words, you have to remember to HideHourglass before leaving the
method, but there are many ways, plus any exceptions, that you might
leave, and it's a pain to remember them all. In VB6 I used
deterministic finalization on an hourglass object:

Sub LongProcess
...
Hourglass.Show
...
End Sub

When the method ended, the object would go out of scope and hide the
hourglass, so there was no need to add this code, and no way to forget
to add it at every exit point.


So I'm looking for a way to accomplish this in .NET. I was thinking
there might be some way to do this:

Sub LongProcess
...
Hourglass.Show()
...
End Sub

and in the Show function, do some magic to figure out what the calling
method is and figure out when it has completed. .NET obviously knows
this, but how can we access it programmatically? Any help much
appreciated. Thanks.

Cheers,
Joshua Frank
 
Joshua Frank said:
Is there any way to tell when the method you're in has exited? This
would be handy for things like:

Try/Finally will do you absolutely fine in this case. Put most of the
code in the Try block, and put the HideHourGlass bit in the Finally
block. However you leave the method, the Finally block will be
executed.
 
Jon said:
Try/Finally will do you absolutely fine in this case. Put most of the
code in the Try block, and put the HideHourGlass bit in the Finally
block. However you leave the method, the Finally block will be
executed.
True, but I think it'd be nicer still to just set it and forget it in
one call without the need to call HideHourglass at all. Perhaps that's
a little compulsive, but I do wonder if it's possible.
 
Joshua Frank said:
True, but I think it'd be nicer still to just set it and forget it in
one call without the need to call HideHourglass at all. Perhaps
that's a little compulsive, but I do wonder if it's possible.

No. There's no deterministic finalization in the framework.

In C# you could abuse IDisposable and write a class to enable you to
write

using (Hourglass glass = new Hourglass())
{
... other code here ...
}

but I don't believe there's an equivalent structure in VB.NET.
 
Jon said:
No. There's no deterministic finalization in the framework.

In C# you could abuse IDisposable and write a class to enable you to
write

using (Hourglass glass = new Hourglass())
{
... other code here ...
}

but I don't believe there's an equivalent structure in VB.NET.
There isn't, although I understand it's coming in VS 2005. But that
would be abuse, and probably more verbose than the Try...Catch design
you proposed. Now I'm just free associating, but shouldn't it be
possible to figure out where on the stack you are, and when the current
frame is popped? Then if you really wanted something to happen when the
method terminated, you could do it. Just wondering...
 
[Using blocks]
There isn't, although I understand it's coming in VS 2005. But that
would be abuse, and probably more verbose than the Try...Catch design
you proposed.

Well, less verbose in the calling code - more verbose in the class
you'd be using.
Now I'm just free associating, but shouldn't it be
possible to figure out where on the stack you are, and when the current
frame is popped?

I don't think so...
Then if you really wanted something to happen when the
method terminated, you could do it. Just wondering...

You could make one method call another method, but you'd still need
Try/Finally to make sure you covered exceptions. The way I see it,
Try/Finally is precisely designed to let you have code which gets
called when you exit a block of code, however you exit it - why
wouldn't you want to use it?
 
It's a little picky, but the reason is to avoid the verbosity in every
function involved:

Hourglass.Show()

instead of

100 Try
101 Hourglass.Show()
102 ...
103 Catch ex As Exception
104 Throw New Exception(ex.Message, ex)
105 Finally
106 Hourglass.Hide()


You have to have the three lines for Try, Catch, and Finally, and you
have to rethrow the exception because otherwise any higher level
exception handlers will never get it.

Also, I've found that you need to write

Throw New Exception(ex.Message, ex)

instead of the simpler

Throw ex

because otherwise the stack tracer thinks the error occurred at line
104, instead of wherever it really did occur. (Actually, it does
anyway, but then you can use the InnerException to figure where the
error really happened.) But of course this makes the stack trace harder
to follow.

So on the whole, I try not to rely on Finally if I don't have to.
[Using blocks]
There isn't, although I understand it's coming in VS 2005. But that
would be abuse, and probably more verbose than the Try...Catch design
you proposed.


Well, less verbose in the calling code - more verbose in the class
you'd be using.

Now I'm just free associating, but shouldn't it be
possible to figure out where on the stack you are, and when the current
frame is popped?


I don't think so...

Then if you really wanted something to happen when the
method terminated, you could do it. Just wondering...


You could make one method call another method, but you'd still need
Try/Finally to make sure you covered exceptions. The way I see it,
Try/Finally is precisely designed to let you have code which gets
called when you exit a block of code, however you exit it - why
wouldn't you want to use it?
 
Joshua Frank said:
It's a little picky, but the reason is to avoid the verbosity in every
function involved:

Hourglass.Show()

instead of

100 Try
101 Hourglass.Show()
102 ...
103 Catch ex As Exception
104 Throw New Exception(ex.Message, ex)
105 Finally
106 Hourglass.Hide()

You don't need the Catch bit, just Try/Finally.
You have to have the three lines for Try, Catch, and Finally, and you
have to rethrow the exception because otherwise any higher level
exception handlers will never get it.

So don't bother with the Catch at all.
Also, I've found that you need to write

Throw New Exception(ex.Message, ex)

instead of the simpler

Throw ex

because otherwise the stack tracer thinks the error occurred at line
104, instead of wherever it really did occur. (Actually, it does
anyway, but then you can use the InnerException to figure where the
error really happened.) But of course this makes the stack trace harder
to follow.

In C# you can just do throw; which doesn't have this problem. It looks
(from a couple of bits of documentation) as if VB.NET doesn't have
this, which is a pity. It's not as bad as all that though, because you
don't need to catch the exception in the first place.
So on the whole, I try not to rely on Finally if I don't have to.

That's a really bad idea when you should be using it virtually every
time you deal with an IDisposable implementation. Fortunately, it's not
nearly as bad as you think, because you don't need to specify a catch
block.
 
So don't bother with the Catch at all.
Interesting. If you omit the Catch, it does correctly report the line
number. Thanks for the tip.
In C# you can just do throw; which doesn't have this problem. It looks
(from a couple of bits of documentation) as if VB.NET doesn't have
this, which is a pity. It's not as bad as all that though, because you
don't need to catch the exception in the first place.
Since you mentioned this, I went back and tried it. VB does have a
Throw, but it doesn't (IMHO) do the right thing. It reports the error
as being on the line with the Throw, and not where the primary exception
was really thrown. But probably there's no need, since omitting Catch
entirely, as you point out, does do the right thing.
That's a really bad idea when you should be using it virtually every
time you deal with an IDisposable implementation. Fortunately, it's not
nearly as bad as you think, because you don't need to specify a catch
block.

It seems to me that one of the main things that .NET accomplishes is to
make memory management simpler. Even in VB6 you could create an object
and forget about it, as it would be reclaimed when it went out of scope
(ignoring circular references and other messy situations). So it seems
like a big step backward to force us to do memory management as if we're
using C:

....
MyObject MyVar = GetExpensiveResource()
MyVar.Use
....

MyVar.Dispose
....


I still think it would be better to employ my original solution of
simply being able to tell when the method completes:

MyObject MyVar = Disposable(GetExpensiveResource())

and then when the method completes it would dispose the object for you.
I guess this is what using accomplishes in C# (currently no equivalent
in VB), but even this is annoying to my taste. If you declare an object
in a method, the scope is that method and the compiler knows that. Why
can't it just Dispose the object when the object goes out of scope? I
can't think of a reason why you wouldn't want this behavior.
 
Joshua Frank said:
It seems to me that one of the main things that .NET accomplishes is to
make memory management simpler. Even in VB6 you could create an object
and forget about it, as it would be reclaimed when it went out of scope
(ignoring circular references and other messy situations). So it seems
like a big step backward to force us to do memory management as if we're
using C:

You don't have to manage memory. You have to manage other resources.
I still think it would be better to employ my original solution of
simply being able to tell when the method completes:

MyObject MyVar = Disposable(GetExpensiveResource())

and then when the method completes it would dispose the object for you.
I guess this is what using accomplishes in C# (currently no equivalent
in VB), but even this is annoying to my taste. If you declare an object
in a method, the scope is that method and the compiler knows that. Why
can't it just Dispose the object when the object goes out of scope? I
can't think of a reason why you wouldn't want this behavior.

The object doesn't go out of scope; the variable does. By that time,
there may well be another variable with a reference to the same object.
 
Back
Top