So I have the following block of code inside a method: (all variables are local)
// ...
try
{
if (postXml != null)
using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
writer.Write(postXml.ToString());
}
catch (WebException ex)
{
HttpWebResponse response = ex.Response as HttpWebResponse;
if (response != null)
result = HandleOtherResponse(response, out status);
else result = HandleBadResponse(ex.ToString(), out status);
}
catch (Exception ex)
{
result = HandleBadResponse(ex.ToString(), out status);
}
if (result == null)
{
try
{
HttpWebResponse response = req.GetResponse() as HttpWebResponse;
result = HandleOtherResponse(response, out status);
}
catch (WebException ex)
{
HttpWebResponse response = ex.Response as HttpWebResponse;
if (response != null)
result = HandleOtherResponse(response, out status);
else result = HandleBadResponse(ex.ToString(), out status);
}
catch (Exception ex)
{
result = HandleBadResponse(ex.ToString(), out status);
}
}
// ...
As you can see, the two try statements are different, but the two sets of catch statements are exactly the same. I've been trying to think of a way that it might be possible to not repeat myself here, but I haven't really thought of a way that wouldn't be significantly slower or just as terrible looking. Wondering if anyone has any ideas.
One way would be to write a "safe" invocation method and pass a func to it:
public T SafeInvocation(Func<T> myMethod)
{
T result = default(T);
try
{
// Invoke method
result = myMethod();
}
catch
{
// Do your common catch here
}
return result;
}
Build an additional overload for Action<T> so that you don't need to have a return type. Then you could invoke it elsewhere, passing methods to your method as arguments (Inception?):
SafeInvocation(() =>
{
if (postXml != null)
using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
writer.Write(postXml.ToString());
}
You could pass an Action into a function that handles the exceptions:
private void HandleErrorsFor(Action action)
{
try
{
action();
}
catch (Exception ex)
{
//repeated exception handling...
{
}
//...
public void DoSomething()
{
HandleErrorsFor(() => {
//try block #1
});
HandleErrorsFor(() => {
//try block #2
});
}
It's a bit easier to read and avoids the repeated code.
You can do something with delegates and cover both try and catch blocks:
static class Program
{
delegate void CodeBlock();
internal delegate void ExceptionCatcher(Exception ex);
private static void Main()
{
CodeBlock b = () => { Console.WriteLine("HELLO WORLD"); };
CodeBlock error = () => { throw new Exception("Exception thrown"); };
ExceptionCatcher silence = exception => { };
ExceptionCatcher e = exception =>
{
var currentColor = Console.BackgroundColor;
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine(exception.Message);
Console.BackgroundColor = currentColor;
};
DRYRunner(b, e);
DRYRunner(error , e);
DRYRunner(error , silence);
Console.ReadLine();
}
static void DRYRunner (CodeBlock block, ExceptionCatcher catcher)
{
try
{
block.Invoke();
}
catch (Exception ex)
{
catcher(ex);
}
}
}
edit: Extending this out, we can create a class to help contain and associate code blocks with their possible exceptions and handlers. You could even create a class of common exception handlers and reference them accordingly, mixing them in with ad-hoc handlers:
class ExceptionHandledDelegate
{
public delegate void CodeBlock();
public delegate void ExceptionCatcher(Exception ex);
public Dictionary<Type, ExceptionCatcher> ExceptionHandlers;
public CodeBlock codeBlock { get; set; }
public void Run()
{
try
{
codeBlock.Invoke();
}
catch (Exception ex)
{
var mn = ex.GetType();
if (ExceptionHandlers.Keys.Contains(mn))
{
ExceptionHandlers[mn](ex);
}
else throw;
}
}
}
class CommonHandlers
{
public static void ArgumentHandler(Exception ex)
{
Console.WriteLine("Handling an argument exception");
}
public static void DivZeroHandler(Exception ex)
{
Console.WriteLine("Please don't divide by zero. It upsets the universe.");
}
}
static class Program
{
private static void Main()
{
var ehd = new ExceptionHandledDelegate
{
codeBlock = () => { throw new ArgumentException("An argument exception has been thrown"); },
ExceptionHandlers = new Dictionary<Type, ExceptionHandledDelegate.ExceptionCatcher>
{
{typeof (ArgumentException), CommonHandlers.ArgumentHandler},
{typeof (DivideByZeroException ),CommonHandlers.DivZeroHandler},
{typeof (Exception), exception => Console.WriteLine("An exception has been thrown")}
}
};
ehd.Run();
ehd.codeBlock = () => { throw new Exception("An exception has been thrown"); };
ehd.Run();
ehd.codeBlock = () =>{var denom = 0; Console.WriteLine(100 / denom);};
ehd.Run();
Console.ReadLine();
}
}
Related
I have a program that calls dozens of methods with varying signatures, but the exception handling inside each one is identical. Is there some way to define a method that can accept a reference to a generic method with various signatures (which rules out a Delegate - right?) and return the object, or void that the method requires? I'm using .NET 4.72.
Here is stripped down version of what I'm currently doing and some pseudo-code of what I'd like to do:
static class StackOverflowQuestion
{
public static void Main(string[] args)
{
// What I'm currently doing:
MethodOne("x");
int ret = MethodTwo(0);
//.
//.
//.
MethodNineteen();
// what I'd like to do is replace MethodOne(), MethodTwo(), ..., Method Nineteen()
// with something like:
RunMethod<void>(MethodOneWork, new object[] {"x"});
ret = RunMethod<int>(MethodTwoWork, new object []{1});
//.
//.
//.
RunMethod<void>(MethodNineteenWork, null);
}
private static void MethodOne(string st)
{
try
{
// the try clause is the only difference between the methods
MethodOneWork(st);
}
catch (MyExceptionA)
{
HandleExceptionA();
return;
}
catch(MyExceptionB)
{
HandleExceptionB();
}
catch(Exception)
{
HandleGenericException();
}
}
private static int MethodTwo(int v)
{
try
{
return MethodTwoWork(v);
}
catch (MyExceptionA)
{
HandleExceptionA();
return -1;
}
catch (MyExceptionB)
{
HandleExceptionB();
return -2;
}
catch(Exception)
{
HandleGenericException();
return 0;
}
}
private static void MethodNineteen()
{
try
{
MethodNineteenWork();
}
catch (MyExceptionA)
{
HandleExceptionA();
return;
}
catch (MyExceptionB)
{
HandleExceptionB();
}
catch(Exception)
{
HandleGenericException();
}
}
/// <summary>
/// Run generic method with generic signature
/// </summary>
private static <T> RunMethod(Delegate MethodxWork, object[] myParams)
{
try
{
new <T>() retVal = MethodxWork(myParams);
return retVal;
}
catch (MyExceptionA)
{
HandleExceptionA();
return new <T>();
}
catch (MyExceptionB)
{
HandleExceptionB();
return new <T>();
}
catch(Exception)
{
HandleGenericException();
return new <T>();
}
}
private static void HandleExceptionB()
{
//handle it
}
private static void HandleExceptionA()
{
//handle it
}
private static void HandleGenericException()
{
//handle it
}
}
internal class MyExceptionB : Exception
{
}
internal class MyExceptionA : Exception
{
}
Sure, just create a few methods whose job it is to handle the exceptions, one for returning results and the other for void, and provide something that does your work.
T Handle<T>(Func<T> call)
{
try
{
return call();
}
catch(YourException ex)
{
return default;
}
}
void Handle(Action call)
{
try
{
call();
}
catch(YourException ex)
{
}
}
After that, you can call your other methods with varying signatures inside there.
var result = Handle(() => SomeCallWithVaryingSignature(...));
Handle(() => SomeOtherCall(...));
I have wrote a simple service to serialize and deserialize classes with the default XmlSerializer. I wanted to do this async but when the XMlSerializer throws an exception inside the Task, it is not caught by the try/catch
public async Task<T> DeserializeAsync<T>(TextReader reader)
{
try
{
return await Task.Run(() =>
{
var serializer = new XmlSerializer(typeof(T));
var result = serializer.Deserialize(reader);
return (T) result;
});
}
catch (Exception e)
{
//Do something with exception
}
}
I have one solution but it can't possibly be the solution to this problem:
public async Task<T> DeserializeAsync<T>(TextReader reader)
{
Exception exception = null;
var result = await Task.Run(
() =>
{
try
{
return (T) new XmlSerializer(typeof(T)).Deserialize(reader);
}
catch (Exception e)
{
exception = e;
return default(T);
}
});
if (exception != null)
{
// handle exception
}
return result;
}
UPDATE: Code that reproduces the error:
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
public class Program
{
private static Serializer _serializer;
static void Main(string[] args)
{
_serializer = new Serializer();
Task.Factory.StartNew(ReadUsers);
Console.ReadKey();
}
private static async Task ReadUsers()
{
var stream = new MemoryStream(Encoding.ASCII.GetBytes(""));
try
{
var user = await _serializer.DeserializeAsync<User>(new StreamReader(stream));
Console.WriteLine(user.Name);
}
catch (Exception e)
{
Console.WriteLine($"Caught exception: {e.Message}");
}
}
}
public class Serializer
{
public async Task<T> DeserializeAsync<T>(TextReader reader)
=> await Task.Run(() => (T) new XmlSerializer(typeof(T)).Deserialize(reader));
}
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
I have a lot of functions that look like this:
public void DoParticularThing(RecurringTaskRunResult result) {
try {
// Do a bunch of stuff
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
So I decided to extract this out in the name of DRY code:
public void RunThing(Action<RecurringTaskRunResult> action, RecurringTaskRunResult result) {
try {
action(result);
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
This way I can call DoParticularThing like this:
RunThing(DoParticularThing, result);
But some of my functions also accept another parameter:
public void DoOtherParticularThing(RecurringTaskRunResult result, List<string> strings) {
try {
// Do a bunch of stuff
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
How can I modify RunThing to optionally accept another parameter?
Perhaps this :
public void RunThing(Action action, RecurringTaskRunResult result) {
try {
action();
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
RunThing(() => DoParticularThing(result), result);
RunThing(() => DoSomethingElse(result, list), result);
You can use params accept any parameters in your function.
public void RunThing(Action<RecurringTaskRunResult> action, RecurringTaskRunResult result, params object[] list) {
try {
action(result);
foreach(var item in list)
{
// Do action with your additional parameter
}
}
catch (Exception e) {
result.Succeeded = false;
result.Results += e.ToString();
db.SaveChanges();
}
}
It looks like in all cases you want RunThing to have access to the RecurringTaskRunResult so that you can set some fields on it, but that you don't need access to any of the other parameters. You could try something like this:
void Action1(RecurringTaskRunResult result) { }
void Action2(RecurringTaskRunResult result, object foo) { }
RecurringTaskRunResult result = ...;
object foo = ...;
RunThing(Action1, result);
RunThing(res => Action2(res, foo), result);
I wrote two functions which look similar, how can I optimize them?
Note:
1.AsyncCompletedEventArgs is the base class of DownloadStringCompletedEventArg and UploadStringCompletedEventArgs.
2.Result property is not in the AsyncCompletedEventArgs.
3.DownloadStringCompletedEventArgs has a Error property, if Error is null, then try to access Result property, the exception occurs.
void fun1(DownloadStringCompletedEventArgs e)
{
try
{
string s = e.Result;
}
catch (WebException eX)
{
HandleWebException();
}
}
void fun2(UploadStringCompletedEventArgs e)
{
try
{
string s = e.Result;
}
catch (WebException eX)
{
HandleWebException();
}
}
You code may be changed to something like below:
void fun1(DownloadStringCompletedEventArgs e) { Process(e); }
void fun2(UploadStringCompletedEventArgs e) { Process(e); }
private void Process(dynamic eventArgs)
{
try
{
string s = eventArgs.Result;
}
catch (WebException e)
{
HandleWebException(e);
}
}
UploadStringCompletedEventArgs and DownloadCompletedEventArgs both extend AsyncCompletedEventArgs but unfortunately the base class does not define the Result property.
A TryX pattern with a result accessor delegate might be appropriate here:
public bool TryGetResult(Func<string> resultAccessor, out string result)
{
try
{
result = resultAccessor();
return true;
}
catch(WebException)
{
HandleWebException();
result = null;
return false;
}
}
void fun1(DownloadStringCompletedEventArgs e)
{
string result;
if (TryGetResult(() => e.Result, out result))
{
// Success
}
}
void fun2(UploadStringCompletedEventArgs e)
{
string result;
if (TryGetResult(() => e.Result, out result))
{
// Success
}
}
I'd recommend trying to work in a check to AsyncCompletedEventArgs.Error, though, as exceptions are quite expensive.
Something like this:
void fun1(DownloadStringCompletedEventArgs e)
{
var result = Process<string>(e);
if (result != null)
{
// TODO your logic here
}
}
void fun2(UploadStringCompletedEventArgs e)
{
var result = Process<string>(e);
if (result != null)
{
// TODO your logic here
}
}
private T Process<T>(AsyncCompletedEventArgs result)
{
if (result.Error != null)
HandleWebException(result.Error);
else if (!result.Cancelled)
{
//var prop = result.GetType().GetProperty("Result");
//return (T) prop.GetValue(result, null);
return (T) ((dynamic)result).Result;
}
//else // TODO handle cancelled
return default(T);
}
Maybe you could write a function that takes a parameter of type AsyncCompletedEventArgs (from which both eventArg classes you use inherit) and then attempt to cast it to the correct type in your code. That would allow you to complete both in the same method, but looking at your code it probably wouldn't have much benefit for you. Good luck!
try
{
using (response = (HttpWebResponse)request.GetResponse())
// Exception is not caught by outer try!
}
catch (Exception ex)
{
// Log
}
EDIT:
// Code for binding IP address:
ServicePoint servicePoint = ServicePointManager.FindServicePoint(uri);
servicePoint.BindIPEndPointDelegate = new BindIPEndPoint(Bind);
//
private IPEndPoint Bind(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
IPAddress address;
if (retryCount < 3)
address = IPAddress.Parse("IPAddressHere");
else
{
address = IPAddress.Any;
throw new Exception("IP is not available,"); // This exception is not caught
}
return new IPEndPoint(address, 0);
}
I could imagine this can happen if you are creating a separate thread within the using block. If an exception is thrown there, be sure to handle it there as well. Otherwise, the outer catch block in this case won't be able to handle it.
class TestClass : IDisposable
{
public void GetTest()
{
throw new Exception("Something bad happened"); // handle this
}
public void Dispose()
{
}
}
class Program
{
static void Main(string[] args)
{
try
{
using (TestClass t = new TestClass())
{
Thread ts = new Thread(new ThreadStart(t.GetTest));
ts.Start();
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
Do you have more code after the using? The using needs one statement or a block { } after the using statement. In the example below any exception inside the using statement will be caught with the try..catch block.
try
{
using (response = (HttpWebResponse)request.GetResponse())
{
....
}
}
catch (Exception ex)
{
}
This works fine. You'll see an exception getting printed by the Console.WriteLine()
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
try
{
using (Bar bar = foo.CreateBar())
{
}
}
catch(Exception exception)
{
Console.WriteLine(exception.Message);
}
}
}
public class Foo
{
public Bar CreateBar()
{
throw new ApplicationException("Something went wrong.");
}
}
public class Bar : IDisposable
{
public void Dispose()
{
}
}
And if you meant that the exception gets thrown inside the using, this works fine to. This will also generate a Console statement:
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
try
{
using (Bar bar = foo.CreateBar())
{
throw new ApplicationException("Something wrong inside the using.");
}
}
catch(Exception exception)
{
Console.WriteLine(exception.Message);
}
}
}
public class Foo
{
public Bar CreateBar()
{
return new Bar();
// throw new ApplicationException("Something went wrong.");
}
}
public class Bar : IDisposable
{
public void Dispose()
{
}
}
The using keyword is the same as try-catch-finally, http://msdn.microsoft.com/en-us/library/yh598w02.aspx. Basically, you have a try-catch-finally nested inside of a try-catch which is why you're probably so confused.
You could just do this instead...
class Program
{
static void Main(string[] args)
{
HttpWebResponse response = new HttpWebResponse();
try
{
response.GetResponse();
}
catch (Exception ex)
{
//do something with the exception
}
finally
{
response.Dispose();
}
}
}