I'm currently loading images in different ways like this:
try {
// way 1
}
catch
{ // way 1 didn't work
try {
// way 2
}
catch
{
// etc.
}
}
I was wondering if there was a cleaner way to do this. Currently it's not a problem but if i add a few more ways it's going to get messy.
Note that the method loading the image is also in a try catch in the same way because it might not be an image.
It's basically trying a bunch of stuff to figure out what it is you dragged into the application.
You can write a method that accepts any number of delegates, attempting all of them and stopping after one of them runs successfully. This abstracts the exception handling into one place, and avoids all of the repetition:
public static void AttemptAll(params Action[] actions)
{
var exceptions = new List<Exception>();
foreach (var action in actions)
{
try
{
action();
return;
}
catch (Exception e)
{
exceptions.Add(e);
}
}
throw new AggregateException(exceptions);
}
This allows you to write:
AttemptAll(Attempt1, Attempt2, Attempt3);
If the methods compute a result you can create a second overload to handle that as well:
public static T AttemptAll<T>(params Func<T>[] actions)
{
var exceptions = new List<Exception>();
foreach (var action in actions)
{
try
{
return action();
}
catch (Exception e)
{
exceptions.Add(e);
}
}
throw new AggregateException(exceptions);
}
Assuming the "different ways" to load the image all throw an exception upon failure, you could iterate through the different ways, until one succeeds. The example below uses a Function<Image> to show a parameterless function that returns an image upon success. In your concrete example, you probably also have parameters into your function.
List<Function<Image>> imageLoaders = LoadTheListSomehow();
foreach (var loader in imageLoaders)
{
try
{
var image = loader();
break; // We successfully loaded the image
}
catch (Exception ex)
{
// Log the exception if desired
}
}
The nesting there does look unnecessary. I would isolate each way of loading an image into its own private method, and then called these methods as delegates in a loop, like this:
private static MyImage LoadFirstWay(string name) {
return ...
}
private static MyImage LoadSecondWay(string name) {
return ...
}
private static MyImage LoadThirdWay(string name) {
return ...
}
...
public MyImage LoadImage(string name) {
Func<string,MyImage>[] waysToLoad = new Func<string,MyImage>[] {
LoadFirstWay
, LoadSecondWay
, LoadThirdWay
};
foreach (var way in waysToLoad) {
try {
return way(name);
} catch (Exception e) {
Console.Error("Warning: loading of '{0}' failed, {1}", name, e.Message);
}
}
return null;
}
Related
I have the following code, but I am not sure what is the right pattern to exit the Execute() method.
The code is working, but the Execute() method is too large.
public void Execute()
{
// load datatable from excel
DataTable data = new();
try
{
data = ExcelReader.ToDataTable(_meta.FullPath, new() { SheetName = _sheetName });
}
// these errors are fine, but the dataset is not relevant and we want exit the execution
catch (ArgumentOutOfRangeException e)
{
if (e.Message.Contains("HeaderRowIndex")) return;
}
catch (ArgumentNullException e)
{
if (e.Message.Contains("Parameter 'sheet'")) return;
}
// execute logic on dataset
// ..
}
I would like to move the load data part of the code into separate method like this, but then I don't know how to end the execution.
public void Execute()
{
// load data
DataTable data = new();
LoadData();
// execute logic on dataset
// ...
}
private DataTable LoadData()
{
try
{
data = ExcelReader.ToDataTable(_meta.FullPath, new() { SheetName = _sheetName });
}
// these errors are fine, but the dataset is not relevant and we want exit the execution => but how?
catch (ArgumentOutOfRangeException e)
{
if (e.Message.Contains("HeaderRowIndex")) return; // will return to Execute() method, but not exit it.
}
catch (ArgumentNullException e)
{
if (e.Message.Contains("Parameter 'sheet'")) return; // will return to Execute() method, but not exit it.
}
}
I think this is very common issue, so what is the recommended way to handle this requirement? Should I create some returning object from the LoadData method, for example
class LoadDataResult
{
public DataTable data {get; set};
public bool IsRelevant {get; set};
}
dataResult = LoadData()
if (!dataResult.IsRelevant) return;
or it is an overkill and easier solution exist (to not populate program with these result objects)?
You can return data in the output parameter and return result of data loading as a primary method output (true for successful load, false for error that is fine):
private bool TryLoadData(out DataTable data)
{
data = null;
try
{
data = ExcelReader.ToDataTable(
_meta.FullPath, new() { SheetName = _sheetName });
return true; // loading succeeded
}
catch (ArgumentOutOfRangeException e)
when (e.Message.Contains("HeaderRowIndex"))
{
// loading failed, continue to Execute method
return false;
}
catch (ArgumentNullException e)
when (e.Message.Contains("Parameter 'sheet'"))
{
// loading failed, continue to Execute method
return false;
}
// otherwise exception propagates to Execute method
}
Usage:
public void Execute()
{
if (TryLoadData(out var data)
{
// execute logic on dataset
}
else
{
// error, but not exception
}
}
I would think about what you are trying to return. In your catch's you can log the error but you don't need to return. All code will flow back to the previous method that called it regardless if it returns or not. You only need to return if you need to pass a value back up to the previous calling method. Otherwise, you can just leave it be!
Let's say you have the following method:
public void Install()
{
CreateItem(Item1)
CreateItem(Item2)
CreateItem(Item3)
}
where CreateItem will throw a ItemAlreadyExistsException if the item already exists, but you want execution to continue to the other two even if that exception is thrown, so you'd probably do something similar to this:
public void Install()
{
var itemsColl = new[] {Item1, Item2, Item3};
foreach (var item in itemsColl)
{
try
{
CreateItem(item);
}
catch (ItemAlreadyExistsException e)
{
// Do nothing or handle exception
}
}
}
Now let's say you also have an Uninstall() method that does the opposite - deletes the items - and that you also have a Repair() method that just calls to Uninstall() and then Install() - with one small difference: on Repair() because you just had a call to Uninstall() before you calling Install() you know that the items should never exist (if they did, they would have gotten deleted by the Uninstall() call) which means now you do care about the ItemAlreadyExistsExceptions and you no longer want to catch them.
In this particular simple example the body of Install() is small/simple enough that it could just be copied to Repair() (although this would create duplication of code), but how would one go about creating something that works for a more complex example without creating duplication of code?
One thing I can think of is creating something like:
public void Install()
{
InternalInstall(false);
}
private void InternalInstall(bool throwOnError)
{
var itemsColl = new[] {Item1, Item2, Item3};
foreach (var item in itemsColl)
{
try
{
CreateItem(item);
}
catch (ItemAlreadyExistsException e)
{
if (throwOnError)
throw;
}
}
}
public void Repair()
{
Uninstall();
InternalInstall(true);
}
But having a parameter decide whether to throw or not is not a very good idea as stated here (even if this is a private method): Throw/do-not-throw an exception based on a parameter - why is this not a good idea?
Any other thoughts?
I think, I'd do it like this
IEnumerable<Item> Install(){
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try{ CreateItem(item); }
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
Something similar for Uninstall, and finally
IEnumerable<Item> Repair(){
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try
{
DeleteItem(item);
CreateItem(item);
}
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
Of course you immediately see where the code duplication is now and how you could improve from there on.
Maybe a little like this:
private IEnumerable<Item> GuardedIterationOfItems( Action<Item> action )
{
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try{
action(item);
}
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
IEnumerable<Item> Install()
{
return GuardedIterationOfItems( CreateItem );
}
IEnumerable<Item> UnInstall()
{
return GuardedIterationOfItems( DeleteItem );
}
IEnumerable<Item> Repair()
{
return GuardedIterationOfItems( x => {
DeleteItem(x);
CreateItem(x);
});
}
Disclaimer: Untested and maybe in need of threadsafety measures if it should be.
How do I make this method into an event?
BarcodeScannerRenderer.cs:
void IScanSuccessCallback.barcodeDetected(MWResult result)
{
if (result != null)
{
try
{
var scan = Element as BarcodeScannerModal;
if (scan == null)
return;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
And pass the value of result into another class, specifically in here:
(BarcodeScanner.cs)
public async Task<object[]> GetResult()
{
TaskCompletionSource<object[]> tcs = new TaskCompletionSource<object[]>();
scanPage.OnScanResult += async (result) =>
{
object[] scanResult = new object[2];
SharedAppSettings.Sounds.PlayBeep();
scanResult[0] = resultFinal.text;
scanResult[1] = resultFinal.typeText;
await PopupNavigation.PopAsync();
tcs.SetResult(scanResult);
};
return await tcs.Task;
}
If you ever wonder what type of Barcode Scanner I am using, it's Manatee Works Barcode Scanner.
This answer will probably have to be adapted to changes to the question, so do not consider it complete:
To raise an event you'd do something like this:
// Given you have a custom EventArgs class ...
// Define an event on which clients can register their handlers
public event EventHandler<BCDetectedEventArgs> BarcodeDetected;
// infoObject should probably be of the type what `scan` is.
protected virtual void OnBarcodeDetected( object infoObject )
{
// Check if there is at least one handler registered
var handler = BarcodeDetected;
if( handler != null )
{
handler(this, new BCDetectedEventArgs(infoObject));
}
}
void IScanSuccessCallback.barcodeDetected(MWResult result)
{
if (result != null)
{
try
{
var scan = Element as BarcodeScannerModal;
if (scan == null)
return;
else
OnBarcodeDetected( scan );
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
See also for reference https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.110).aspx
The part in BarcodeScanner.cs is a little more tricky because your snippet suggests a "polling" design. You would first have to adapt to register to the event from above snippet and act on the event in an appropriate handler method.
I have the following:
using CommonSettings = MyProject.Commons.Settings;
public class Foo
{
public static void DoSomething(string str)
{
//How do I make sure that the setting exists first?
object setting = CommonSettings.Default[str];
DoSomethingElse(setting);
}
}
If you are using a SettingsPropertyCollection you have to loop and check which settings exists yourself it seems, since it doesn't have any Contains-method.
private bool DoesSettingExist(string settingName)
{
return Properties.Settings.Default.Properties.Cast<SettingsProperty>().Any(prop => prop.Name == settingName);
}
Depending on what type CommomSettings.Default is, a simple null check should be fine:
if(setting != null)
DoSomethingElse(setting);
If you want to check BEFORE trying to retrieve the setting, you need to post the Type of CommonSettings.Default. It looks like a Dictionary so you might be able to get away with:
if(CommonSettings.Default.ContainsKey(str))
{
DoSomethingElse(CommonSettings.Default[str]);
}
try
{
var x = Settings.Default[bonusMalusTypeKey]);
}
catch (SettingsPropertyNotFoundException ex)
{
// Ignore this exception (return default value that was set)
}
This is how you deal with it:
if(CommonSettings.Default.Properties[str] != null)
{
//Hooray, we found it!
}
else
{
//This is a 'no go'
}
You could do the following:
public static void DoSomething(string str)
{
object setting = null;
Try
{
setting = CommonSettings.Default[str];
}
catch(Exception ex)
{
Console.out.write(ex.Message);
}
if(setting != null)
{
DoSomethingElse(setting);
}
}
This would ensure the setting exists - you could go a bit further and try and catch the exact excetion - e.g catch(IndexOutOfBoundsException ex)
Is it possible to use return statement in try block?.How,What is the use of the statement.
You can return from within a try block, but keep in mind that the code in the finally clause will be executed before returning from the method. For example, calling MessageBox.Show(test().ToString()); using the method below will cause two message boxes to appear (the first displaying "3" and the second displaying "1").
int test()
{
try
{
return 1;
throw new Exception();
}
catch (Exception e)
{
return 2;
}
finally
{
MessageBox.Show("3");
}
}
Sure, you can use return in a try block, and the syntax is just like everywhere else.
try
{
return 0;
}
catch (Exception e)
{
// handle exception
}
Yes.
I can use local variables without having to widen their scope, for example.
int Foo(string bar) {
try {
int biz = int.Parse(bar);
return biz;
} catch(...) {
// Handle bad `bar`
}
}
An answer for this question is Yes.
As an example for this you can refer to the following question:
finally and return
Hope you also get a clarification.
Sure, you can do it like:
public string X(..)
{
try
{
//do something
return value;
}
catch(Exception ex)
{
throw;
//or return here
}
}