"Else" equivalent in foreach loop when ienumerable is empty - c#

Assuming the ienumerable is not null, a foreach loop simply won't execute if that ienumerable is empty. But instead, I need to run other code if the collection is empty. Here's sample code which works flawlessly:
List<string> theList = new List<string>() {};
if (theList.Count > 0) {
foreach (var item in theList) {
//do stuff
}
} else {
//throw exception or do whatever else
}
Is there anyway to shorten this up via out-of-the-box C#, an Extension Method, etc? In my head I was thinking the following would be cool, but obviously it doesn't work:
List<string> theList = new List<string>() {};
foreach (var item in theList) {
//do stuff
} else {
//throw exception or do whatever else
}
EDIT: My solution thanks to insight from Maarten: The following will throw an exception if the collection is null or empty (if you want to simply ignore cases where the collection is null or empty, use a ternary operator in the foreach)
static class Extension {
public static IEnumerable<T> FailIfNullOrEmpty<T>(this IEnumerable<T> collection) {
if (collection == null || !collection.Any())
throw new Exception("Collection is null or empty");
return collection;
}
}
class Program {
List<string> theList = new List<string>() { "a" };
foreach (var item in theList.FailIfNullOrEmpty()) {
//do stuff
}
}

If you really wanted to achieve this, you could create an extension method (like you said yourself).
class Program {
static void Main(string[] args) {
List<string> data = new List<string>();
foreach (var item in data.FailIfEmpty(new Exception("List is empty"))) {
// do stuff
}
}
}
public static class Extensions {
public static IEnumerable<T> FailIfEmpty<T>(this IEnumerable<T> collection, Exception exception) {
if (!collection.Any()) {
throw exception;
}
return collection;
}
}

You can throw the exception beforehand, without having to write the else block:
if(mylist.Count == 0)
throw new Exception("Test");
foreach(var currItem in mylist)
currItem.DoStuff();
The execution flow won't reach the loop if the exception has been raised.

Related

Refactor to generic method with Predicate<T> and inner condition variable

Consider removing duplicated elements of List from a specific class like below:
private List<MyClass> RemoveDuplicatedMyClass(List<MyClass> myObjects)
{
List<MyClass> uniqueMyClasses = new List<MyClass>();
foreach (MyClass item in myObjects)
{
if (uniqueMyClasses.FindAll(itm => itm.myAttribute == item.myAttribute).Count == 0)
{
uniqueMyClasses.Add(item);
}
}
return uniqueMyClasses;
}
I want to refactor RemoveDuplicatedMyClass to a generic version RemoveDuplicatedItems like below:
public static List<T> RemoveDuplicatedItems<T>(List<T> items, Predicate<T> match)
{
if (items == null)
{
return new List<T>();
}
List<T> uniqueItems = new List<T>();
foreach (T item in items)
{
// Check if item exists (= already added)! If not add to unique list.
if (uniqueItems.FindAll(match).Count < 1)
{
uniqueItems.Add(item);
}
}
return uniqueItems;
}
Problem: How can I get access to Predicate<T> match with the inner T item?
As guys mentioned in comments, it's a good idea to use Enumerable.DistinctBy and one solution is to use dynamic objects:
static List<dynamic> RemoveDuplicatedItems(List<dynamic>? items)
{
if (items == null)
{
return new List<dynamic>();
}
return items.DistinctBy(x=>x.MyAttribute).ToList();
}
and another and I think better option is to use abstraction, if you have some common properties between your classes you can create interface and define type of T as inheritor of that interface:
static List<T> RemoveDuplicatedItems<T>(List<T>? items) where T:ISomeCommonInterface
{
if (items == null)
{
return new List<T>();
}
return items.DistinctBy(x=>x.MyAttribute).ToList();;
}

Foreach throws NullReferenceException on not null IEnumerable with elements

I have encountered in my code similiar situation to the one presented in code below. The problem is that for some reason iterating in foreach loop throws NullReferenceException.
My question is, why this happens?
If I create iterator that returns empty element myself, foreach handles it, and simply prints empty line.
Result of following code is: test, test, NullReferenceException.
using System;
using System.Collections.Generic;
using System.Linq;
public class NestedB
{
public string Test {get;set;}
}
public class NestedA
{
public List<NestedB> NestedCollection {get;set;}
}
public class Program
{
public static void Main()
{
var listOfA = new List<NestedA>
{
new NestedA
{
NestedCollection = new List<NestedB>
{
new NestedB {Test = "test"},
new NestedB {Test = "test"}
}
},
new NestedA ()
};
var listOfB = listOfA.SelectMany(x => x.NestedCollection);
foreach (var item in listOfB)
{
if (item != null)
{
Console.WriteLine(item.Test);
}
}
}
}
Stacktrace:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at Program.Main()
Command terminated by signal 6
This is the problem:
listOfA.SelectMany(x => x.NestedCollection)
Your second NestedA instance doesn't have a NestedCollection, so it's trying to find "all the items in a null reference". You'd have exactly the same problem if you did this manually:
var nestedA = new NestedA();
// This will throw an exception, because nestedA.NestedCollectoin is null
foreach (var nestedB in nestedA.NestedCollection)
{
}
The simplest fix to this would be to make NestedCollection a read-only property, but initialize it to start with:
public List<NestedB> NestedCollection { get; } = new List<NestedB>();
Then you'll need to modify the initialization of your first NestedA to use a collection initializer:
new NestedA
{
NestedCollection =
{
new NestedB { Test = "test" },
new NestedB { Test = "test" }
}
}
If you don't want to do that, you could change the SelectMany call instead:
var listOfB = listOfA.SelectMany(x => x.NestedCollection ?? Enumerable.Empty<NestedB>())
The implementation of SelectMany is something like this:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
{
if (source == null)
throw Error.ArgumentNull(nameof (source));
if (selector == null)
throw Error.ArgumentNull(nameof (selector));
return Enumerable.SelectManyIterator<TSource, TResult>(source, selector);
}
private static IEnumerable<TResult> SelectManyIterator<TSource, TResult>(
IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector)
{
foreach (TSource source1 in source)
{
foreach (TResult result in selector(source1)) // The error throws here
yield return result;
}
}
Note the comment line. The selector(source1) will return a null for the second NestedA item and this line will try to get the enumerator of the null item(foreach). That's why you got the error.
To complement the existing answers:
Compilation optimization and runtime optimization can cause inaccuracies in the reported line numbers. It is useful to examine not just the enumerable, but also the foreach body for possible dereferenced nulls, especially if iterating over a (statically declared) array.

C# - check if List<> is initialized

I have function that accept out List<int> list as parameter. How can I check if list is initialized or not?
This code gives me the Use of unassigned out parameter 'list' error:
public void CheckList(out List<int> list)
{
if (list == null) {
list = List<int>();
}
//Rest of the code
}
Facts that I have checked:
Variables passed as out arguments do not have to be initialized before being passed in a method call. However, the called method is
required to assign a value before the method returns. out parameter
modifier
Edit:
I want my method to be able to accept both options: list with elemtns and append aditional elements to it or in other case to initialize list and add elements to it.
If you are dealing with out argument then most certainly it isn't initialized because the method should initialize it.
If it was passed by "ref", then you would check it.
Why not use a wrapper?
public void CheckListWrapper(ref List<int> list)
{
if(list == null)
{
CheckList(out list);
}
else
{
//append whatever
}
}
public void CheckList(out List<int> list)
{
list = List<int>();
//Rest of the code
}
I added a new parameter for sameList and it will work for you so
what about this one. There is no more way to accept without Initialization.
private static void Main()
{
List<int> i=null;
CheckList(out i,i);
Console.WriteLine(i[0]);
}
public static void CheckList(out List<int> list,List<int> sameList)
{
list = sameList;
if(list==null)
{
//Intialize
list = new List<int>();
list.Add(1);
}
else
{
//append
list.Add(12);
}
//Rest of the code
}
Try the following code:
bool IsInitialised(List myList) {
if ( (myList!= null) && (!myList.Any()) )
{
return true;
}
return false;
}
A linq-less way will be:
if(myList != null && myList.Count == 0){
// The list is empty. Add something here
}
From your calling method like Main:
Pseudo code. Testmethod(ref list) and TestMethod(list) have different signature so they both compile.
if(IsInitialised(list))
Call TestMethod(ref list);
Else call TestMethod(list);

Override the default behaviour of GetEnumerator

I have a requirement where I need to know the calling method to the GetEnumerator().
The best way I could think would be possibly overriding the default behaviour to GetEnumerator to one that I create i.e GetEnumerator([CallerMemberName]string caller = null) but I cannot seem to do this as anything calling it still goes to the original one.
public class MyItems : IEnumerable<string>
{
private List<string> items = new List<string>();
public MyItems()
{
items.Add("One");
items.Add("Two");
items.Add("Three");
items.Add("Four");
items.Add("Five");
items.Add("Six");
}
public IEnumerator<string> GetEnumerator()
{
return items.GetEnumerator();
}
public IEnumerator<string> GetEnumerator([CallerMemberName]string caller = null)
{
var method = caller;
return items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
Example of some calling code could be
private void button1_click(object sender,EventArgs e)
{
MyItems items = new MyItems();
foreach (var item in items)
{
}
}
The aim is that I would want to know for example "button1_click" in the GetEnumerator() method
I don't think it's possible to do exactly what you want to do, since foreach, to my knowledge, always calls the GetEnumerator() without any arguments. However, I see two possibilities to your issue
You can use a StackTrace to get the calling method:
public IEnumerator<string> GetEnumerator()
{
StackTrace stackTrace = new StackTrace();
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
return items.GetEnumerator();
}
or you can use another method instead of the GetEnumerator() which takes the [CallerMemberName] attribute.
public IEnumerable<string> Iterate([CallerMemberName]string caller = null)
{
Console.WriteLine(caller);
return items;
}
foreach (var myItem in items.Iterate())
{
//..
}
seems like , you need to use StackTrace Class
StackTrace st = new StackTrace();
var fr = st.GetFrames();
if(fr != null && fr.Any() &&fr.Count() >1)
{
MessageBox.Show(fr.ElementAt(1).GetMethod().Name);
}

C# is there a foreach oneliner available?

I just want to know if there is a foreach oneliner in C#, like the if oneliner (exp) ? then : else.
If you're dealing with an array then you can use the built-in static ForEach method:
Array.ForEach(yourArray, x => Console.WriteLine(x));
If you're dealing with a List<T> then you can use the built-in ForEach instance method:
yourList.ForEach(x => Console.WriteLine(x));
There's nothing built-in that'll work against any arbitrary IEnumerable<T> sequence, but it's easy enough to roll your own extension method if you feel that you need it:
yourSequence.ForEach(x => Console.WriteLine(x));
// ...
public static class EnumerableExtensions
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
foreach (T item in source)
{
action(item);
}
}
}
List.ForEach Method
Imagine you have three variables and you want to set the same property of them all in only one go:
foreach (var item in new [] {labelA, labelB, labelC})
{
item.Property= Value;
}
It is the equivalent of doing:
foreach (var item in new List<SomeType>(){labelA, labelB, labelC})
{
item.Property= Value;
}
foreach line-liners could be achieved with LINQ extension methods. For example:
instead of:
var result = new List<string>();
foreach (var item in someCollection)
{
result.Add(item.Title);
}
you could:
var result = someCollection.Select(x => x.Title).ToList();
Sure, you can use something like List<>.ForEach:
List<String> s = new List<string>();
s.Add("This");
s.Add("Is");
s.Add("Some");
s.Add("Data");
s.ForEach(_string => Console.WriteLine(_string));
The primary difference between if and the ?operator is that if is a statement, while ? produces an expression. I.e. you can do this:
var _ = (exp) ? then : else; // ok
but not this:
var _ = if (exp) { then; } else { else; }; // error
So if you are looking for something like a foreach expression, there is no .NET type that can naturally return except for void, but there are no values of void type, so you can equally just write:
foreach (var item in collection) process(item);
In many functional languages, a Unit type is used instead of void which is a type with only one value. You can emulate this in .NET and create your own foreach expression:
class Unit
{
public override bool Equals(object obj)
{
return true;
}
public override int GetHashCode()
{
return 0;
}
}
public static class EnumerableEx
{
public static Unit ForEach<TSource>(
this IEnumerable<TSource> source,
Action<TSource> action)
{
foreach (var item in source)
{
action(item);
}
return new Unit();
}
}
However there hardly exists any use-case for such expressions.

Categories