Try that!



  • Bernie was tasked with adding some new functionality, and thus investigated the code base to find the best extension points. He stumbled upon code "trying" quite a lot:

    private async void Timer_Elapsed(object _sender, ElapsedEventArgs _e)
    {
    	try
    	{
    		await Task.Run(() => DoSomething());
    	}
    	finally
    	{
    		m_Timer.Start();
    	}
    }
    

    ...

    private void DoSomething()
    {
    	try
    	{
    		...
    		ISomething something = FindSomething(...);
    		...
    		Run(...);
    	}
    	catch (Exception ex)
    	{
    		Logger.LogException(Name, ex);
    	}
    }
    

    ...

    private ISomething FindSomething(...)
    {
    	switch (...)
    	{
    		case ...:
    			...
    			return new Something(...);
    		default:
    			throw new SpecialException("Blah blah blah.");
    	}
    }
    

    ...

    private void Run(...)
    {
    	string exceptionMessages = "";
    
    	Task taskMain = Task.Run(() => ...);
    
    	try
    	{
    		taskMain.Wait();
    	}
    	catch (AggregateException ex)
    	{
    		foreach (Exception innerException in ex.InnerExceptions)
    		{
    			exceptionMessages += innerException.Message + " / " + innerException.StackTrace + " # ";
    		}
    	}
    
    	if (taskMain.Exception?.InnerException != null)
    	{
    		exceptionMessages += taskMain.Exception.InnerException.Message + " / " + taskMain.Exception.InnerException.StackTrace + " # ";
    	}
    	if (!string.IsNullOrEmpty(exceptionMessages))
    	{
    		throw new SpecialException($"Error(s) in special task: {exceptionMessages}");
    	}
    }
    

    The DoSomething method will never throw any exception: all exceptions raised therein are also caught and logged there.
    Hence it is useful to enclose the Task in the Timer event handler with a try..finally, isn't it?

    The Run method runs a task and catches its exceptions. It takes a lot of care to collect all the exception messages and stack traces, feeds them into a new exception, which unspecifically gets caught in DoSomething, and logged (and the Logger has some functionality to take care of AggregateExceptions, InnerExceptions, StackTraces, and exception messages, too - with better formatting, of course).

    By the way, what would happen if some exception entered that Timer event handler? Well, there is a finally: that should re-enable the timer. Without a catch, that's very useful when such a ThreadException just crashed the application.

    Oh sanctissimi Wilhelmus, Theodorus et Fredericus. Deliberate me a ho malo. Amen.


  • Notification Spam Recipient

    Odd, apparently you've posted seven things, but I'm privy to only two of them....



  • @tsaukpaetra said in Try that!:

    Odd, apparently you've posted seven things, but I'm privy to only two of them....

    Looks like an import bug.



  • @tsaukpaetra Well, I don't see them either... We're here on the Daily WTF, aren't we?


  • ♿ (Parody)

    @berniethebernie I don't see them either, which is tightly related to why @ben_lubar says it's an import bug.


  • Notification Spam Recipient

    @boomzilla said in Try that!:

    @berniethebernie I don't see them either, which is tightly related to why @ben_lubar says it's an import bug.

    I can only assume they're posts that had NULL characters in them....



  • @berniethebernie said in Try that!:

    The DoSomething method will never throw any exception: all exceptions raised therein are also caught and logged there.
    Hence it is useful to enclose the Task in the Timer event handler with a try..finally, isn't it?

    It may be true that "DoSomething" will never throw, but that does not mean the same thing about Task.Run(...) :)


Log in to reply