Method that handles exceptions from BeginInvoke? - c#

Sometime you need to run specific code on specific threads, for example winforms. To get the code running on the UI thread you need something like this :
this.BeginInvoke(new MethodInvoker(() =>
{
try
{
//code
}
catch(Exception ex)
{
HandleException(ex);
}
}
SynchornixationContext is another way to do the same thing.
Say that we know that we need to run specific code in the UI thread and we have a given way of handling the exceptions that are thrown on this UI thread(BeginInvoke is not blocking so exceptions will not be transfered). How could we create a method that makes the same thing but simplier like this :
RunOnUIThread(MyMethod);
The RunOnUIThread will contains mor or less the same code as the first example in this code.
Is it possible to create a method like this? And if so How?

You can write some nice extension methods like this
public static class ControlExtension
{
public static IAsyncResult BeginInvokeWithExceptionHandling(this Control control, Action method, Action<Exception> exceptionHandler)
{
if (control == null) throw new ArgumentNullException("control");
if (method == null) throw new ArgumentNullException("method");
if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
return control.BeginInvoke(new MethodInvoker(() =>
{
try
{
method();
}
catch (Exception ex)
{
exceptionHandler(ex);
}
}));
}
public static IAsyncResult BeginInvokeWithExceptionHandling<T>(this Control control, Delegate method, Action<Exception> exceptionHandler, params object[] args)
{
if (control == null) throw new ArgumentNullException("control");
if (method == null) throw new ArgumentNullException("method");
if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
return control.BeginInvoke(new MethodInvoker(() =>
{
try
{
method.DynamicInvoke(args);
}
catch (Exception ex)
{
exceptionHandler(ex);
}
}));
}
}
How to use:
private void HandleException(Exception ex)
{
}
private void MyMethod()
{
}
this.BeginInvokeWithExceptionHandling(MyMethod, HandleException);
Note: Due to Delegate.DynamicInvoke this may be little less performing, you can fix it with strong typed delegate. It is also worth noting that control.BeginInvoke is also internally using Delegate.DynamicInvoke if it can't find what the delegate type is.

public static void InvokeControlAction<t>(t cont, Action<t> action) where t : Control
{
if (cont.InvokeRequired)
{ cont.Invoke(new Action<t, Action<t>>(InvokeControlAction),
new object[] { cont, action }); }
else
{ action(cont); }
}
CodeProject Reference

I ended upp with this based on SriramĀ“s suggestion :
public static void SendToUIThread(Action method, bool UseExceptionHandling = true)
{
if (method == null)
throw new ArgumentNullException("method is missing");
_threadSyncContext.Send(new SendOrPostCallback(delegate(object state)
{
if (UseExceptionHandling)
{
try
{
method();
}
catch (Exception ex)
{
ErrorController.Instance.LogAndDisplayException(ex, true);
}
}
else
method();
}), null);
}
public static void PostOnUIThread(this Control control, Action method, bool UseExceptionHandling = true)
{
if (method == null)
throw new ArgumentNullException("method is missing");
if (control.InvokeRequired)
PostOnUIThread(method, UseExceptionHandling);
else
{
if (UseExceptionHandling)
{
try { method(); }
catch (Exception ex) { ErrorController.Instance.LogAndDisplayException(ex, true); }
}
else
method();
}
}

Related

How to handle various exceptions coming from an external function

How do I handle, invoke exceptions from the add function.
The external function will throw two different exceptions depending on the conditions.
I would like to handle each of these exceptions differently in main.
Thanks for helps.
My example code:
static void Main(string[] args)
{
try
{
add(0, 0);
}
catch(Exception ex)
{
if(Exception 1){
//...
}
if(Exception 2){
//...
}
}
}
public static int add (int a, int b)
{
int result = a + b;
if (result == 0)
{
throw new Exception("Exception 1");
}
if(result > 10)
{
throw new Exception("Exception 2");
}
return result;
}
You have to use the message you assign in the add method, and then check the condition inside the main or another place you want The code with a solution:
static void Main(string[] args)
{
try
{
add(0, 0);
}
catch (Exception ex)
{
Console.WriteLine("catch");
if (ex.Message == "Exception 1")
{
Console.WriteLine("1");
}
if (ex.Message == "Exception 2")
{
Console.WriteLine("2");
}
}
}
public static int add(int a, int b)
{
int result = a + b;
if (result == 0)
{
throw new Exception("Exception 1");
}
if (result > 10)
{
throw new Exception("Exception 2");
}
return result;
}

The type arguments for method MyFunction<T>(Func<T>) cannot be inferred from the usage

I am trying out this piece of code below from:
Is there a way to check if a file is in use?
But, it gives error:
The type arguments for method TimeoutFileAction(Func) cannot be inferred from the usage.
Any idea how to fix this?
TimeoutFileAction(() => { System.IO.File.etc...; return null; } );
Reusable method that times out after 2 seconds
private T TimeoutFileAction<T>(Func<T> func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
return func();
}
catch (System.IO.IOException exception)
{
//ignore, or log somewhere if you want to
}
}
return default(T);
}
You MUST have an output other than Type of void.
When you do this: () => { System.IO.File.etc...; return null; } the output type is void and you cannot have that for a Func<T>. If you want a Void Type then use Action.
If you want both void and T, then just write an overflow method. Se Code below:
public static void Main()
{
var today = new DateTime(2021, 10, 25, 5, 40, 0);
Console.WriteLine(today.AddHours(7).AddMinutes(36));
TimeoutFileAction(() => { Test(); });
TimeoutFileAction(Test);
}
private static string Test() => "Test";
private static void TimeoutFileAction(Action func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
func();
}
catch (IOException exception)
{
//ignore, or log somewhere if you want to
}
}
}
private static T TimeoutFileAction<T>(Func<T> func)
{
var started = DateTime.UtcNow;
while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
{
try
{
return func();
}
catch (IOException exception)
{
//ignore, or log somewhere if you want to
}
}
return default(T);
}

Do I need to implement try/catch expections for testing this method? Not really sure where to start?

I'm unit testing code for an application and I'm confused on how to test try/catch exceptions. What would be a good approach for testing this method?
public static Exception Create<TException>(string format, params object[] args) where TException : Exception
{
var type = typeof(TException);
try
{
if (type == typeof(ArgumentOutOfRangeException))
{
return (TException)Activator.CreateInstance(type, String.Empty, String.Format(format, args));
}
if (type == typeof(ArgumentNullException))
{
var name = format;
return (TException)Activator.CreateInstance(type, String.Empty, Constants.Strings.ValueCannotBeNull.FormatWith(name));
}
return (TException)Activator.CreateInstance(type, String.Format(format, args));
}
catch (MissingMethodException)
{
try
{
return (TException)Activator.CreateInstance(type);
}
catch (MissingMethodException ex)
{
return new Exception(ParameterlessConstructorMissing.FormatWith(type), ex);
}
}
}

C# Pass Parameter to Lambda

In the following, I need to pass nextDB to the Lambda expression in Retry:
Retry.Do(() =>
{
string nextDB = dbList.Next();
using (DataBaseProxy repo = new DataBaseProxy(nextDB))
{
return repo.DoSomething();
}
});
How do I do that? Here is my Retry class:
public static class Retry
{
public static void Do(
Action action,
int retryCount = 3)
{
Do<object>(() =>
{
action();
return null;
}, retryCount);
}
public static T Do<T>(
Func<T> action,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
return action();
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
I think you want to be using Action<T> here. For example:
public static void Do<T>(
Action<T> action,
T param,
int retryCount = 3)
{
var exceptions = new List<Exception>();
for (int retry = 0; retry < retryCount; retry++)
{
try
{
action(param);
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
You would call this function like this:
Do(s => {
Console.WriteLine(s);
}, "test", 3);
Based on your comments, it seems that you want to pass in multiple databases and try each one in succession until you find one that works. One simple option would be to remove to retryCount and instead pass in your array.
public static void Do<T>(
Action<T> action,
IEnumerable<T> items)
{
var exceptions = new List<Exception>();
foreach(var item in items)
{
try
{
action(item);
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
And now you call it something like this:
Do(s => {
Console.WriteLine(s);
}, new[] { "db1", "db2", "db3" });

Adjusting the Invoke call to cater for methods that return void and non-void types

How would I adjust the following Invoke call so that it caters for methods that return void and non-void types?
At the moment ErrorHandlingComponent.Invoke expects a Func<T> as its first parameter. I've found that when I'm trying to pass it a void method, the compiler complains.
public static T Invoke<T>(Func<T> func, int tryCount, TimeSpan tryInterval)
{
if (tryCount < 1)
{
throw new ArgumentOutOfRangeException("tryCount");
}
while (true)
{
try
{
return func();
}
catch (Exception ex)
{
if (--tryCount > 0)
{
Thread.Sleep(tryInterval);
continue;
}
LogError(ex.ToString());
throw;
}
}
}
You can't. A Func delegate is designed so that it always returns something.
The easiest way would be to create an overload of the Invoke method that takes an Action delegate rather than a Func:
public static void Invoke(Action action, int tryCount, TimeSpan tryInterval)
{
if (tryCount < 1)
{
throw new ArgumentOutOfRangeException("tryCount");
}
while (true)
{
try
{
action();
return;
}
catch (Exception ex)
{
if (--tryCount > 0)
{
Thread.Sleep(tryInterval);
continue;
}
LogError(ex.ToString());
throw;
}
}
}

Categories