Should Dispose be called when rethrowing an unhandled exception? - c#

Supposed I have a class like the below:
public class DisposableClass : IDisposable()
{
private readonly Timer timer;
DisposableClass()
{
this.timer = new Timer(s => cb(s), s, 1000, 1000);
}
Init()
{
try
{
// Do some initialization here that is not done in ctor.
}
catch (Exception)
{
// Log error.
throw;
}
finally
{
// Is this correct?
this.Dispose();
}
}
public void Dispose()
{
this.timer?.Dispose();
}
}
My question is whether the finally clause necessary (or should not have at all) in the above case, of for any non-constructor method when throwing an unhandled exception. Thanks.
EDIT:
In the answer, please address the issues depending on Init() being public,protected, private visibility levels.

Related

Cannot access a disposed object, on a static variable?

I'm using the popup from the Maui.Community.Toolkit to display a waiting animation.
public static class WaitingService
{
private static WaitingPopup waitingPopup = new();
async public static Task ShowWaitingPopupAsync()
{
try
{
//2nd time this is called throws the exception
await Application.Current.MainPage.ShowPopupAsync(waitingPopup);
}
catch (Exception ex)
{
//cannot access a disposed object
await Application.Current.MainPage.DisplayAlert("Exception", ex.Message, "OK");
}
}
public static void HideWaitingPopup()
{
waitingPopup.Close();
}
}
The second time around that I call ShowWaitingPopupAsync() I get the disposed object exception. My understanding is that static classes/variables are persistent, and aren't disposed of until application exit, right?

SynchronizationContext and DispatcherUnhandledException

I am having a case where an exception thrown in UI thread doesn't get catched in the calling thread.
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
namespace SynchronisationContextAndExceptionWPF
{
public partial class MainWindow : Window
{
private readonly SynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = SynchronizationContext.Current;
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
throw;
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
}
First I thought that cannot possible (all documentation I found said that I can catch exceptions there).
After some reasearch I found the problem: My application uses an UnhandledExceptionHandler. That handles the DispatcherUnhandledException-Event. I am showing some information to the user and set e.Handled = true;:
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace SynchronisationContextAndExceptionWPF
{
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private static void App_DispatcherUnhandledException(
object sender,
DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine("Catched Exception in UnhandledExceptionHandler.");
// This line makes the difference:
e.Handled = true;
}
}
}
So the question: why is the DispatcherUnhandledException-Event raised even if I handle it?
How would you solve this situation?
If you have a lot of controls, you can generate a new class which remenbers the special exception variable. So you only need to change the initialization of your _synchronizationContext (hopefully only once at your base class of your controls).
public partial class MainWindow : Window
{
private readonly MySynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = new MySynchronizationContext(SynchronizationContext.Current);
}
private void button_Click(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
DoSomethingOnUiThreadThatThrowsException();
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
class MySynchronizationContext
{
SynchronizationContext innerContext;
public MySynchronizationContext(SynchronizationContext ctx)
{
innerContext = ctx;
}
public virtual void Send(SendOrPostCallback d, object state)
{
Exception threadException = null;
try
{
innerContext.Send(_ =>
{
try
{
d.Invoke(state);
}
catch (Exception exception)
{
threadException = exception;
}
}, null);
}
catch (Exception ex)
{
}
if (threadException != null)
{
throw new Exception("Synchronization error", threadException);
}
}
}
Inside your lambda expression you can set an Exception variable and check this variable later at the calling thread. If it was set, then throw exception at calling thread.
private void button_Click(object sender, RoutedEventArgs e)
{
Exception threadException = null;
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception ex)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
threadException = ex;
//throw; --> don't throw exception here; otherwise you will get DispatcherUnhandledException twice.
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
if(threadException != null)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw threadException; //throw you previously catched exception here.
}
}
Kind Regards,
Daniel

A single thread to which you can subscribe methods, to be executed in an unordered fashion

I need the following logic implemented:
a thread to which you can subscribe/unsubscribe methods at runtime.
It's fine for all these methods to have an header such as (Object sender, EventArgs e) and to return void.
These methods scope must be the scope of the class where they are defined lexically.
There's no guarantee about the order of execution
I've come up with the following implementation, which seems to do exactly what I need: basically I start an internal thread which triggers an event each x milliseconds. You can subscribe/unsubscribe delegates to this event through appropriate methods.
Before sticking to it I'd like to know if there may be subtle issues following this approach.
public class Orchestrator
{
private Thread _mainThread;
private event MethodDelegate _mainEvent;
public delegate void MethodDelegate (Object sender, EventArgs e);
private bool _stop = false;
private short _ms = 100;
public short PollingInterval { get { return _ms; }
set
{
_ms = value;
}
}
public Orchestrator()
{
_mainThread = new Thread(new ThreadStart(_execute));
}
public void Start()
{
_stop = false;
_mainThread.Start();
}
public void Stop()
{
_stop = true;
}
public void Clear()
{
_mainEvent = null;
}
public void Push(MethodDelegate method)
{
_mainEvent += method;
}
public void Pop(MethodDelegate method)
{
_mainEvent -= method;
}
private void _execute()
{
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
}
}
That's basically fine. You need to make _stop volatile. In C# the event accessor methods are thread-safe so that works fine.
The exception handling is very questionable. Do you really want to spam errors to the console? Define an event OnError and report errors to the consumer of your class.
You could use a timer or await Task.Delay to save a thread. This would make sense if there are a lot of such class instances at the same time. If there is just one this is likely not worth the effort.
You have a race condition which could cause a NullReferenceException, in:
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
Some other thread could unsubscribe from the event or call Clear() inbetween if (_mainEvent != null) and the call of _mainEvent.
To avoid this, you should copy _mainEvent into a local variable and check that against null, and use that instead:
var mainEvent = _mainEvent;
if (mainEvent != null)
try
{
mainEvent(this, new EventArgs());
In any case, I think you should be using a Timer for this rather than rolling-your-own.

Return feedback from an event which is being waited on

In it's simplicity what I am trying to do is handle "Doing Something" by firing off a process on a seperate thread to do what I need to do and waiting for an event to be raised to say "I have finished doing what I need to do". In the EventArgs though I will have a property for any errors which may be encountered during the process. Here is a simplified example of my situation.
public class MessageHandler
{
private AutoResetEvent MessageHasSent = new AutoResetEvent(false);
public void SendMessage()
{
MessageSender ms = new MessageSender();
ms.MessageSent += new EventHandler<MessageSentEventArgs>(MessageHandler_MessageSent);
Thread t = new Thread(ms.Send());
t.Start();
MessageHasSent.WaitOne();
//Do some check here
//Same again but for "Message recieved"
}
void MessageHandler_MessageSent(object sender, MessageSentEventArgs e)
{
if (e.Errors.Count != 0)
{
//What can I do here to return to the next step after waitone?
}
else
MessageHasSent.Set();
}
}
public class MessageSender
{
public event EventHandler<MessageSentEventArgs> MessageSent;
public void Send()
{
//Do some method which could potentiallialy return a List<Error>
MessageSent(this, new MessageSentEventArgs() { Errors = new List<Error>() });
}
}
public class Error { }
public class MessageSentEventArgs : EventArgs
{
public List<Error> Errors;
}
Essentially once the event has been raised from Send the code will continute, however I want some way of the event giving feedback, potentially using the MessageHasSent. I have tried different methods, I thought if I called Close instead of Set it would perhaps allow me to access something such as IsClosed. You could throw an exception or set a flag outside of the scope of the event to check but I feel like this is dirty.
Any suggestions?
Using the TPL isn't applicable in my case as I am using .NET 3.5.
Since it seems that this entire section of code is already running in a background thread, and you're doing nothing more than starting up a new thread just so that you can wait for it to finish, you'd be better off just calling Send directly, rather than asynchronously.
You don't need to fire off an event when you're completed.
You don't need to signal the main thread when it needs to continue.
You don't need to log the exceptions in a List, you can just throw them and catch them in SendMessage with a try/catch block.
This will do what you want:
public class MessageHandler
{
private AutoResetEvent MessageHasSent = new AutoResetEvent(false);
private bool IsSuccess = false;
public void SendMessage()
{
MessageSender ms = new MessageSender();
ms.MessageSent += new EventHandler<MessageSentEventArgs>(MessageHandler_MessageSent);
Thread t = new Thread(ms.Send());
t.Start();
MessageHasSent.WaitOne();
if(IsSuccess)
//wohooo
else
//oh crap
//Same again but for "Message recieved"
}
void MessageHandler_MessageSent(object sender, MessageSentEventArgs e)
{
IsSuccess = e.Errors.Count == 0;
MessageHasSent.Set();
}
}
public class MessageSender
{
public event EventHandler<MessageSentEventArgs> MessageSent;
public void Send()
{
//Do some method which could potentiallialy return a List<Error>
MessageSent(this, new MessageSentEventArgs() { Errors = new List<Error>() });
}
}
public class Error { }
public class MessageSentEventArgs : EventArgs
{
public List<Error> Errors;
}

Exception handling for Singleton Events

I am using a singleton pattern for a global event manager class that is not handling exceptions in an acceptable manner.
If an exception is thrown in the code called by one of the events being executed, I always get a Exception has been thrown by the target of an invocation. error. This error contains no information related to the original exception, making it extremely difficult to debug any errors.
Is there some way to pass the original exception information back to the event manager?
public class ApplicationSettings
{
private static EventManager _manager = new EventManager();
public static EventManager EventManager
{
get { return _manager; }
}
}
The event manager class:
public class EventManager
{
public event EventHandler<ReportExecutionArgs> ExecuteReportCurrentPage;
public event EventHandler<ReportExecutionArgs> ExecuteReportNewPage;
public virtual void OnExecuteReportCurrentPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportCurrentPage != null)
this.ExecuteReportCurrentPage(sender, e);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public virtual void OnExecuteReportNewPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportNewPage != null)
this.ExecuteReportNewPage(sender, e);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Some other class will handle these events
ApplicationSettings.EventManager.ExecuteReportNewPage += new EventHandler<ReportExecutionArgs>(reportOpenedNewPage);
private void reportOpenedNewPage(object sender, ReportExecutionArgs e)
{
//something in this code throws an error
LitePage page = new LitePage();
_tabs.AddPage(page);
Report report = setReport(page, e);
}
EDIT
Just to clarify, the try/catch blocks in the OnExecuteReport methods are not catching the exception.
A TargetInvocationException such as the one you describe will almost always have the originating exception in it's InnerException.

Categories