Can I trap an exception in a LINQ projection? - c#

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
}
}
}
}

Related

Make using statement usable for multiple disposable objects

I have a bunch of text files in a folder, and all of them should have identical headers. In other words the first 100 lines of all files should be identical. So I wrote a function to check this condition:
private static bool CheckHeaders(string folderPath, int headersCount)
{
var enumerators = Directory.EnumerateFiles(folderPath)
.Select(f => File.ReadLines(f).GetEnumerator())
.ToArray();
//using (enumerators)
//{
for (int i = 0; i < headersCount; i++)
{
foreach (var e in enumerators)
{
if (!e.MoveNext()) return false;
}
var values = enumerators.Select(e => e.Current);
if (values.Distinct().Count() > 1) return false;
}
return true;
//}
}
The reason I am using enumerators is memory efficiency. Instead of loading all file contents in memory I enumerate the files concurrently line-by-line until a mismatch is found, or all headers have been examined.
My problem is evident by the commented lines of code. I would like to utilize a using block to safely dispose all the enumerators, but unfortunately using (enumerators) doesn't compile. Apparently using can handle only a single disposable object. I know that I can dispose the enumerators manually, by wrapping the whole thing in a try-finally block, and running the disposing logic in a loop inside finally, but is seems awkward. Is there any mechanism I could employ to make the using statement a viable option in this case?
Update
I just realized that my function has a serious flaw. The construction of the enumerators is not robust. A locked file can cause an exception, while some enumerators have already been created. These enumerators will not be disposed. This is something I want to fix. I am thinking about something like this:
var enumerators = Directory.EnumerateFiles(folderPath)
.ToDisposables(f => File.ReadLines(f).GetEnumerator());
The extension method ToDisposables should ensure that in case of an exception no disposables are left undisposed.
You can create a disposable-wrapper over your enumerators:
class DisposableEnumerable : IDisposable
{
private IEnumerable<IDisposable> items;
public event UnhandledExceptionEventHandler DisposalFailed;
public DisposableEnumerable(IEnumerable<IDisposable> items) => this.items = items;
public void Dispose()
{
foreach (var item in items)
{
try
{
item.Dispose();
}
catch (Exception e)
{
var tmp = DisposalFailed;
tmp?.Invoke(this, new UnhandledExceptionEventArgs(e, false));
}
}
}
}
and use it with the lowest impact to your code:
private static bool CheckHeaders(string folderPath, int headersCount)
{
var enumerators = Directory.EnumerateFiles(folderPath)
.Select(f => File.ReadLines(f).GetEnumerator())
.ToArray();
using (var disposable = new DisposableEnumerable(enumerators))
{
for (int i = 0; i < headersCount; i++)
{
foreach (var e in enumerators)
{
if (!e.MoveNext()) return false;
}
var values = enumerators.Select(e => e.Current);
if (values.Distinct().Count() > 1) return false;
}
return true;
}
}
The thing is you have to dispose those objects separately one by one anyway. But it's up to you where to encapsulate that logic. And the code I've suggested has no manual try-finally,)
To the second part of the question. If I get you right this should be sufficient:
static class DisposableHelper
{
public static IEnumerable<TResult> ToDisposable<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, TResult> selector) where TResult : IDisposable
{
var exceptions = new List<Exception>();
var result = new List<TResult>();
foreach (var i in source)
{
try { result.Add(selector(i)); }
catch (Exception e) { exceptions.Add(e); }
}
if (exceptions.Count == 0)
return result;
foreach (var i in result)
{
try { i.Dispose(); }
catch (Exception e) { exceptions.Add(e); }
}
throw new AggregateException(exceptions);
}
}
Usage:
private static bool CheckHeaders(string folderPath, int headersCount)
{
var enumerators = Directory.EnumerateFiles(folderPath)
.ToDisposable(f => File.ReadLines(f).GetEnumerator())
.ToArray();
using (new DisposableEnumerable(enumerators))
{
for (int i = 0; i < headersCount; i++)
{
foreach (var e in enumerators)
{
if (!e.MoveNext()) return false;
}
var values = enumerators.Select(e => e.Current);
if (values.Distinct().Count() > 1) return false;
}
return true;
}
}
and
try
{
CheckHeaders(folderPath, headersCount);
}
catch(AggregateException e)
{
// Prompt to fix errors and try again
}
I'm going to suggest an approach that uses recursive calls to Zip to allow parallel enumeration of a normal IEnumerable<string> without the need to resort to using IEnumerator<string>.
bool Zipper(IEnumerable<IEnumerable<string>> sources, int take)
{
IEnumerable<string> ZipperImpl(IEnumerable<IEnumerable<string>> ss)
=> (!ss.Skip(1).Any())
? ss.First().Take(take)
: ss.First().Take(take).Zip(
ZipperImpl(ss.Skip(1)),
(x, y) => (x == null || y == null || x != y) ? null : x);
var matching_lines = ZipperImpl(sources).TakeWhile(x => x != null).ToArray();
return matching_lines.Length == take;
}
Now build up your enumerables:
IEnumerable<string>[] enumerables =
Directory
.EnumerateFiles(folderPath)
.Select(f => File.ReadLines(f))
.ToArray();
Now it's simple to call:
bool headers_match = Zipper(enumerables, 100);
Here's a trace of running this code against three files with more than 4 lines:
Ben Petering at 5:28 PM ACST
Ben Petering at 5:28 PM ACST
Ben Petering at 5:28 PM ACST
From a call 2019-05-23, James mentioned he’d like the ability to edit the current shipping price rules (eg in shipping_rules.xml) via the admin.
From a call 2019-05-23, James mentioned he’d like the ability to edit the current shipping price rules (eg in shipping_rules.xml) via the admin.
From a call 2019-05-23, James mentioned he’d like the ability to edit the current shipping price rules (eg in shipping_rules.xml) via the admin.
He also mentioned he’d like to be able to set different shipping price rules for a given time window, e.g. Jan 1 to Jan 30.
He also mentioned he’d like to be able to set different shipping price rules for a given time window, e.g. Jan 1 to Jan 30.
He also mentioned he’d like to be able to set different shipping price rules for a given time window, e.g. Jan 1 to Jan 30.
These storyishes should be considered when choosing the appropriate module to use.
These storyishes should be considered when choosing the appropriate module to use.X
These storyishes should be considered when choosing the appropriate module to use.
Note that the enumerations stop when they encountered a mismatch header in the 4th line on the second file. All enumerations then stopped.
Creating an IDisposable wrapper as #Alex suggested is correct. It needs just a logic to dispose already opened files if some of them is locked and probably some logic for error states. Maybe something like this (error state logic is very simple):
public class HeaderChecker : IDisposable
{
private readonly string _folderPath;
private readonly int _headersCount;
private string _lockedFile;
private readonly List<IEnumerator<string>> _files = new List<IEnumerator<string>>();
public HeaderChecker(string folderPath, int headersCount)
{
_folderPath = folderPath;
_headersCount = headersCount;
}
public string LockedFile => _lockedFile;
public bool CheckFiles()
{
_lockedFile = null;
if (!TryOpenFiles())
{
return false;
}
if (_files.Count == 0)
{
return true; // Not sure what to return here.
}
for (int i = 0; i < _headersCount; i++)
{
if (!_files[0].MoveNext()) return false;
string currentLine = _files[0].Current;
for (int fileIndex = 1; fileIndex < _files.Count; fileIndex++)
{
if (!_files[fileIndex].MoveNext()) return false;
if (_files[fileIndex].Current != currentLine) return false;
}
}
return true;
}
private bool TryOpenFiles()
{
bool result = true;
foreach (string file in Directory.EnumerateFiles(_folderPath))
{
try
{
_files.Add(File.ReadLines(file).GetEnumerator());
}
catch
{
_lockedFile = file;
result = false;
break;
}
}
if (!result)
{
DisposeCore(); // Close already opened files.
}
return result;
}
private void DisposeCore()
{
foreach (var item in _files)
{
try
{
item.Dispose();
}
catch
{
}
}
_files.Clear();
}
public void Dispose()
{
DisposeCore();
}
}
// Usage
using (var checker = new HeaderChecker(folderPath, headersCount))
{
if (!checker.CheckFiles())
{
if (checker.LockedFile is null)
{
// Error while opening files.
}
else
{
// Headers do not match.
}
}
}
I also removed .Select() and .Distinct() when checking the lines. The first just iterates over the enumerators array - the same as foreach above it, so you are enumerating this array twice. Then creates a new list of lines and .Distinct() enumerates over it.

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 :)

List<T>Get Chunk Number being executed

I am breaking a list into chunks and processing it as below:
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
do something
}
catch
{
print error
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
foreach (var item in sourceList)
{
chunkReturn.Add(item);
if (chunkReturn.Count == chunkSize)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
if (chunkReturn.Any())
{
yield return chunkReturn;
}
}
}
If there is an error, I wish to run the chunk again. Is it possible to find the particular chunk number where we received the error and run that again ?
The batches have to be executed in sequential order .So if batch#2 generates an error, then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good .
List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
try
{
//do something
}
catch
{
//print error
failedChunks.Add(partiallist);
}
}
// attempt to re-process failed chunks here
I propose this answer based on your comment to Aaron's answer.
The batches have to be executed in sequential order .So if 2 is a problem , then I need to be able to run 2 again, if it fails again. I just need to get out of the loop for good.
foreach (var partialist in breaklistinchunks(chunksize))
{
int fails = 0;
bool success = false;
do
{
try
{
// do your action
success = true; // should be on the last line before the 'catch'
}
catch
{
fails += 1;
// do something about error before running again
}
}while (!success && fails < 2);
// exit the iteration if not successful and fails is 2
if (!success && fails >= 2)
break;
}
I made a possible solution for you if you don't mind switching from Enumerable to Queue, which kind of fits given the requirements...
void Main()
{
var list = new Queue<int>();
list.Enqueue(1);
list.Enqueue(2);
list.Enqueue(3);
list.Enqueue(4);
list.Enqueue(5);
var random = new Random();
int chunksize = 2;
foreach (var chunk in list.BreakListinChunks(chunksize))
{
foreach (var item in chunk)
{
try
{
if(random.Next(0, 3) == 0) // 1 in 3 chance of error
throw new Exception(item + " is a problem");
else
Console.WriteLine (item + " is OK");
}
catch (Exception ex)
{
Console.WriteLine (ex.Message);
list.Enqueue(item);
}
}
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
{
List<T> chunkReturn = new List<T>(chunkSize);
while(sourceList.Count > 0)
{
chunkReturn.Add(sourceList.Dequeue());
if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
{
yield return chunkReturn;
chunkReturn = new List<T>(chunkSize);
}
}
}
}
Outputs
1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK
One possibility would be to use a for loop instead of a foreach loop and use the counter as a means to determine where an error occurred. Then you could continue from where you left off.
You can use break to exit out of the loop as soon as a chunk fails twice:
foreach (var partialList in breaklistinchunks(chunksize))
{
if(!TryOperation(partialList) && !TryOperation(partialList))
{
break;
}
}
private bool TryOperation<T>(List<T> list)
{
try
{
// do something
}
catch
{
// print error
return false;
}
return true;
}
You could even make the loop into a one-liner with LINQ, but it is generally bad practice to combine LINQ with side-effects, and it's not very readable:
breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));

C#: Collection was modified; enumeration operation may not execute [duplicate]

This question already has answers here:
How to remove elements from a generic list while iterating over it?
(28 answers)
Closed 9 years ago.
My goal is to delete a user from the user list in my application.But i cannot get to the bottom of this error. Some one plz bail me out.
if (txtEmailID.Text.Length > 0)
{
users = UserRespository.GetUserName(txtEmailID.Text);
bool isUserAvailable=false;
foreach (EduvisionUser aUser in users) // Exception thrown in this line
{
isUserAvailable = true;
if(!aUser.Activated)
{
users.Remove(aUser);
}
}
if (users.Count == 0 && isUserAvailable)
{
DeactivatedUserMessage();
return;
}
}
You can't modify a collection while you're iterating over it with a foreach loop. Typical options:
Use a for loop instead
Create a separate collection of the items you want to act on, then iterate over that.
Example of the second approach:
List<EduvisionUser> usersToRemove = new List<EduvisionUser>();
foreach (EduvisionUser aUser in users) --->***Exception thrown in this line***
{
isUserAvailable = true;
if(!aUser.Activated)
{
usersToRemove.Add(aUser);
}
}
foreach (EduvisionUser userToRemove in usersToRemove)
{
users.Remove(userToRemove);
}
Another alternative, if you're using List<T> is to use List<T>.RemoveAll:
isUserAvailable = users.Count > 0;
users.RemoveAll(user => !user.Activated);
You are trying to delete a user from the list you are looping trough.
this is impossible. Best is to create a new list and add the good ones in it instead of deleting the bad ones
if (txtEmailID.Text.Length > 0)
{
//#new list
List<EduvisionUser> listOfAcceptedUsers = new List<EduvisionUser>()**
users = UserRespository.GetUserName(txtEmailID.Text);
bool isUserAvailable=false;
foreach (EduvisionUser aUser in users) --->***Exception thrown in this line***
{
isUserAvailable = true;
//Add user to list instead of deleting
if(aUser.Activated)
{
ListOfAcceptedUsers.Add(aUser);
}
}
//check new list instead of old one
if (ListOfAcceptedUsers.Count == 0 && isUserAvailable)
{
DeactivatedUserMessage();
return;
}
}
you can do it like this. Use for instead foreach
for( int i =0; i< users.Count; i++ ) --->***Exception thrown in this line***
{
EduvisionUser aUser = users[i];
isUserAvailable = true;
if(!aUser.Activated)
{
users.Remove(aUser);
i--;
}
}
You cannot modify the collection while enumerating. Instead of removing select only what you need and leave the Garbage Collector take care of the rest:
users = users.Where(x => x.Activated);
Or even better, select only what you need from the repository:
users = UserRespository.GetUserName(txtEmailID.Text).Where(x => x.Activated);
My goal is to delete a WorkCalendar from the WorkCalendar but when select Wc that has WorkHour thrown an exception like this:" Collection was modified; enumeration operation may not execute." Any ideas? thanks for the help
Delete method:
try
{
if (!this.DataWorkspace.ApplicationData.WorkCalendars.CanDelete)
{
this.ShowMessageBox("", "", MessageBoxOption.Ok);
return;
}
if (this.WorkCalendars.SelectedItem != null)
{
if ((this.WorkCalendars.SelectedItem.FindCalendarWPs.Count() > 0) || (this.WorkCalendars.SelectedItem.FindCalendarWPs1.Count() > 0))
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
RadWindow.Alert(" ");
});
return;
}
var y = DataWorkspace.ApplicationData.WorkCalendarDays.Where(w => w.WorkCalendar.Id == WorkCalendars.SelectedItem.Id).Execute().AsEnumerable();
foreach (var item in y)
{
if(item.WorkingHoursCollection != null && item.WorkingHoursCollection.Count() > 0)
foreach (var WH in item.WorkingHoursCollection)
{
WH.Delete();
}
item.Delete();
}
if (this.WorkCalendars.SelectedItem == this.DataWorkspace.ApplicationData.WorkCalendars.Where(U => U.Id == this.WorkCalendars.SelectedItem.Id).SingleOrDefault())
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
RadWindow.Alert(" ");
});
return;
}
this.WorkCalendars.SelectedItem.Delete();
this.Save();
}
}
catch (Exception ex)
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke
(() =>
{
var msg = new LightSwitchApplication.Presentation.GeneralViews.ExceptionMessage();
msg.DataContext = ex;
msg.ShowDialog();
});
}

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

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.

Categories