Is it bad to use nested Try..Catch blocks like this? - c#

Is this a bad idea? Is there a better way to achieve the same effect?
// assume that "name" is a string passed as a parameter to this code block
try
{
MainsDataContext dx = new MainsDataContext();
try
{
Main m = dx.Main.Single(s => s.Name == name);
return m.ID;
}
catch (InvalidOperationException)
{
Guid g = Guid.NewGuid();
Main s = new Main
{
Name = name,
ID = g
};
dx.Mains.InsertOnSubmit(s);
dx.SubmitChanges();
return g;
}
}
catch (Exception ex)
{
// handle this
}
The objective here is to get the ID of a record if it exists, otherwise create that record and return it's ID.

You should use SingleOrDefault, that way if a record doesn't exist it will return the default value for the class which is null.
MainsDataContext dx = null;
try
{
dx = new MainsDataContext();
Main m = dx.Main.SingleOrDefault(s => s.Name == name);
if ( m == null)
{
Guid g = Guid.NewGuid();
m = new Main
{
Name = name,
ID = g
};
dx.Mains.InsertOnSubmit(m);
dx.SubmitChanges();
}
return m.ID;
}
catch (Exception ex)
{
// handle this
}
finally
{
if(dx != null)
dx.Dispose();
}
it is a good idea to use the using keyword when using a DataContext
using ( MainsDataContext dx = new MainsDataContext())
{
Main m = dx.Main.SingleOrDefault(s => s.Name == name);
if ( m == null)
{
Guid g = Guid.NewGuid();
m = new Main
{
Name = name,
ID = g
};
dx.Mains.InsertOnSubmit(m);
dx.SubmitChanges();
}
return m.ID;
}

Main m = dx.Main.SingleOrDefault(s => s.Name == name);
if (m == default(Main))
{
// it does not exist
}
else
{
// it does exist
}
It is not apparent from the question if the type Main is a class or a struct (EDIT: I just realized that actually it must be a class), hence I used default() instead of just comparing to null.

My question would be what code you intend to put in here:
// handle this
With the first catch block, you know that Single() threw an InvalidOperationException because the sequence contains more than one element or is empty.
In the second, you could get all kinds of errors. Null reference, data access, etc. How are you going to handle these?
Only catch what you know how to handle, and be as specific in the exception type as you can.

Anyways, I think nested Try Catch blocks are good, like sibling Catch blocks each catching a different problem. It's good to be specific about errors. The catch-all should be only a safety net for production.

No, but you might want to refector the inner block into an external method.

Related

Having trouble with an ICollection/IEnumerable operation - won't remove an occurrence

I'm using a FastObjectListView to enter S/Ns of units to a Disposition (sold, RMA, etc) and I enter a constant for the first S/N - "(Enter Serial)"
I'm using this same model in another section of code (RMA) but I'm missing something when trying to do the same operation for Disposition.
public UnitHistory RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<UnitHistory> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitHistories = seq.ToList();
if (unitHistories.Any())
{
List<UnitHistory> collection = new List<UnitHistory>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitHistories[0]);
AssociatedUnits.Clear();
foreach (UnitHistory history in collection)
{
AssociatedUnits.Add(history);
}
unitHistories[0].Disposition = null;
DisassociatedUnits.Add(unitHistories[0]);
unitHistories[0].Unit.UnitHistory.Remove(unitHistories[0]);
return unitHistories[0];
}
return null;
}
The code won't remove unitHistories[0] from collection.
This model does work in the following code:
public RmaRepairNotes RemoveUnit(Unit unit)
{
if (unit == null)
{
return null;
}
IEnumerable<RmaRepairNotes> seq = AssociatedUnits.Where(p => p.Unit.Equals(unit));
var unitRmaHistories = seq.ToList();
if (unitRmaHistories.Any())
{
List<RmaRepairNotes> collection = new List<RmaRepairNotes>();
collection.AddRange(AssociatedUnits);
collection.Remove(unitRmaHistories[0]);
AssociatedUnits.Clear();
foreach (RmaRepairNotes note in collection)
{
AssociatedUnits.Add(note);
}
unitRmaHistories[0].Rma = null;
DisassociatedUnits.Add(unitRmaHistories[0]);
unitRmaHistories[0].Unit.RmaRepairNotes.Remove(unitRmaHistories[0]);
return unitRmaHistories[0];
}
return null;
}
AssociatedUnits is an ICollection in both classes.
EDIT - SOLUTION: I found a logic error in the Equals code of the UnitHistory class. Now it functions perfectly.
The UnitHistory Class had a logic error in the Equals function. Now that objects could be identified as being equal, the code functions perfectly.

How to handle this exception in a cleaner way?

I've been trying to enumerate through a properties of a class and getting their values in a List of strings.
But i faced a problem where i get a NullReferenceException when the value is null from the properties
I Managed to Fix that by that solution, but still i don't see that as a clean code.
I Wonder if this can be implemented in a cleaner and more professional way.
private int CalculateScore()
{
var score = 0;
var answers = new List<string>();
foreach (var prop in typeof(TypesSheet).GetProperties())
{
// WHEN STRING IS MISSING IT BREAKS
try
{
var answer = prop.GetValue(_typesSheet).ToString();
answers.Add(answer);
}
catch
{
continue;
}
}
if (_gameMode == GameMode.SinglePlayer)
{
foreach (var answer in answers)
{
if (string.IsNullOrEmpty(answer))
continue;
score = score + 10;
}
return score;
}
}
Replace:
// WHEN STRING IS MISSING IT BREAKS
try
{
var answer = prop.GetValue(_typesSheet).ToString();
answers.Add(answer);
}
catch
{
continue;
}
With:
var value = prop.GetValue(_typesSheet);
if (null != value)
{
answers.Add(value.toString());
}
if (prop.GetValue(_typesheets) != null) {
answers.Add(prop.GetValue(_typesheets));
}
The error was caused prop.GetValue(_typesSheet) might be null. when you use ToString method will get
nullreferenceexception
You can try to use linq instead of the foreach.
var answers =
typeof(TypesSheet).GetProperties()
.Select(x => x.GetValue(_typesSheet))
.Where(x=> x!= null)
.Select(x=> x.ToString());
Use Safe Navigation Operator (available in C# 6)
var answer = prop.GetValue(_typesSheet)?.ToString();
if (!string.IsNullOrEmpty(answer)) answers.Add(answer);
Linq version
var answers = typeof(TypesSheet)
.GetProperties()
.Select(prop => prop.GetValue(_typesSheet)?.ToString())
.Where(answer => !string.IsNullOrEmpty(answer))
.ToList();

Overlapping printing of an IEnumerable collection

I'm reading the contents of an XML file into an IEnumerable collection (array) and I need to print each iteration (block of like XML data) on a separate page.
I'm using the Print() function and e.HasMorePages. My problem is that the foreach loops through all iterations of the IEnumerable collection for each print so I'm printing the correct number of pages but each page contains all iterations on top of each other instead of one per page. Can anyone give me an idea for a solution or a better way to manage this process?
Here's the pertinent portion of the code...
// Print Employee General info
foreach (EmployeeInfo itm in GEmployeeXGD.GetEmployeeGeneralData())
{
try
{
empFirstName = itm.FirstName;
empLastName = itm.LastName;
empMidInitial = itm.MidInitial;
etc…
// Set field coordinates for each employee
// ******* Employee's general information ********
PointF empFirstNameLoc = new PointF(430, 271);
PointF empLastNameLoc = new PointF(600, 271);
PointF empMidInitialLoc = new PointF(563, 271);
etc…
// Send field text data
using (Font courierFont = new Font("Courier", 10, FontStyle.Bold))
{
e.Graphics.DrawString(empFirstName, courierFont, Brushes.Black, empFirstNameLoc);
e.Graphics.DrawString(empLastName, courierFont, Brushes.Black, empLastNameLoc);
e.Graphics.DrawString(empMidInitial, courierFont, Brushes.Black, empMidInitialLoc);
etc…
}
}
catch (Exception error) { MessageBox.Show(error.ToString()); }
e.HasMorePages = (records < Globals.totalRecordCount);
}
That's helpful Joel, thanks.
GEmployeeXGD reverences a class with a single method. The method reads in the XML data that I need and populates the IEnumerable<> collection as an array. Here's the method..
public Array GetEmployeeGeneralData()
{
// XML source file
var xmlEmployeeFile = File.ReadAllText("Corrections.xml");
XDocument employeeDoc = XDocument.Parse(xmlEmployeeFile);
XElement w2cEmployeeDat = employeeDoc.Element("CorrectedDAta");
EmployeeInfo[] employeeGenInfo = null;
if (w2cEmployeeDat != null)
{
IEnumerable<XElement> employeeRecords = w2cEmployeeDat.Elements("Employee");
try
{
employeeGenInfo = (from itm in employeeRecords
select new EmployeeInfo()
{
FirstName = (itm.Element("FirstName") != null) ? itm.Element("FirstName").Value : string.Empty,
LastName = (itm.Element("LastName") != null) ? itm.Element("LastName").Value : string.Empty,
MidInitial = (itm.Element("MidInitial") != null) ? itm.Element("MidInitial").Value : string.Empty,
etc…
}).ToArray<EmployeeInfo>();
}
catch (Exception) { MessageBox.Show(error.ToString()); }
}
Globals.SetRecordCount(employeeGenInfo.Count<EmployeeInfo>());
recordCount = Globals.totalRecordCount;
return employeeGenInfo;
}
You need to keep track of what page you are on, and then do something like this:
var items = GEmployeeXGD.GetEmployeeGeneralData().Skip( (pageNumber-1) * numberItemsPerPage).Take(numberOfItemsPerPage);
foreach (EmployeeInfo itm in items)
{
//...
}
Even better if you can avoid calling that same method over and over, and keep the same IEnumerable across individual pages. But to demonstrate this, I'd need to see more of the context of the class where this method lives, and know more about how GEmployeeXGD works.

Find exception hiding/swallowing in C# code in VS2013

is there some way built in function/extension/tool to find all exception hidings/exception swallowing in C# solution(ASP.NET WebForms)n in VS2013.
Thanks
EDIT:
I have existing solution in which some programmers use hide/swallow exceptions(empty catch, catch only with some useless code). And I am looking for some way to find all these places in code, analyze them, and then fix them.
You can write some code using Roslyn to handle this pretty easily.
I actually wrote some code to do exactly that for a friend. It was my first attempt at using the Roslyn SDK, so my code is probably a terrible mess, but it was definitely functional.
static void Main(string[] args)
{
var result = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseFile(#"..\..\Test.cs");
var root = result.GetRoot();
var exceptionNodes = FindCatchNodes(root);
foreach (var node in exceptionNodes)
{
var line = node.GetLocation().GetLineSpan().StartLinePosition.Line + 1;
if (IsTotallyEmptyCatch(node))
{
Console.WriteLine("Totally empty catch: line {0}", line);
}
if (JustRethrows(node))
{
Console.WriteLine("Pointless rethrow: line {0}", line);
}
}
}
static List<SyntaxNodeOrToken> FindCatchNodes(SyntaxNodeOrToken node)
{
var exceptions = new List<SyntaxNodeOrToken>();
var isCatchBlock = node.IsKind(SyntaxKind.CatchClause);
if (isCatchBlock)
{
exceptions.Add(node);
}
foreach (var result in node.ChildNodesAndTokens().Select(FindCatchNodes).Where(result => result != null))
{
exceptions.AddRange(result);
}
return exceptions;
}
static bool IsTotallyEmptyCatch(SyntaxNodeOrToken catchBlock)
{
var block = catchBlock.ChildNodesAndTokens().First(t => t.CSharpKind() == SyntaxKind.Block);
var children = block.ChildNodesAndTokens();
return (children.Count == 2 && children.Any(c => c.CSharpKind() == SyntaxKind.OpenBraceToken) &&
children.Any(c => c.CSharpKind() == SyntaxKind.CloseBraceToken));
}
static bool JustRethrows(SyntaxNodeOrToken catchBlock)
{
var block = catchBlock.ChildNodesAndTokens().First(t => t.CSharpKind() == SyntaxKind.Block);
var children = block.ChildNodesAndTokens();
return (children.Count == 3 && children.Any(c => c.CSharpKind() == SyntaxKind.OpenBraceToken) &&
children.Any(c => c.CSharpKind() == SyntaxKind.CloseBraceToken) && children.Any(c=>c.CSharpKind() == SyntaxKind.ThrowStatement));
}
Given this test file:
using System;
namespace RoslynTest
{
public class Test
{
public void Foo()
{
try
{
var x = 0;
}
catch
{
}
}
public void Bar()
{
try
{
var x = 0;
}
catch (Exception ex)
{
throw;
}
}
public void Baz()
{
try
{
var x = 0;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
The output is:
Totally empty catch: ....\Test.cs: line 12
Pointless rethrow: ....\Test.cs: line 24
Pointless rethrow: ....\Test.cs: line 37
I don't know about the built-in methods. But you can write your own tool to find such places. Just regex all your files in solution and count catch and throw. There should be the same amount for each file :)

Can I trap an exception in a LINQ projection?

Say I write a linq query for info about the hidden files on my C drive:
var q2 =
from c in Directory.EnumerateFiles("C:\\")
where Regex.IsMatch(c, #"^C:\\\.")
select c;
var q3 =
from c in q2
let info = new
{
File = c,
FileSecurity = File.GetAccessControl(c),
FileAttributes = File.GetAttributes(c),
CreatedUTC = File.GetCreationTimeUtc(c),
AccessedUTC = File.GetLastAccessTimeUtc(c),
ModifiedUTC = File.GetLastWriteTimeUtc(c)
}
select info;
The above is an example of logic that might want to keep going when an exception is caught, but I don't know how to get that to happen in this style of C# programming (or if its possible).
Conceptually I want some kind of "continue" statement that can be put in the body of a catch block surrounding a LINQ query.
try
{
// LINQ QUERY
}
catch(Exception ex)
{
Logger.Log("error...");
continue;
}
Due to the lazy nature of LINQ you might need to try/catch when you start consuming the iterator and not when building the query:
var q3 = ...
try
{
foreach (var item in q3)
{
...
}
}
catch(Exception ex)
{
}
The Directory.EnumerateFiles simply returns an IEnumerable<string> and no evaluation happens until you start iterating over it.
UPDATE:
To avoid breaking out of the loop if an exception is thrown you could do the following:
static void Main()
{
var q = Enumerable.Range(1, 5).Select(x =>
{
if (x % 2 == 0)
{
throw new Exception();
}
return x;
});
using (var enumerator = q.GetEnumerator())
{
while (true)
{
try
{
bool hasNext = enumerator.MoveNext();
if (!hasNext)
{
break;
}
Console.WriteLine(enumerator.Current);
}
catch (Exception ex)
{
// TODO: do something with the exception here
}
}
}
}

Categories