I recently decided to try and write my own implementation of Linq, which then lead me on to trying to solve some of the problems we have in our code base at work. Our code is littered with the following (obviously a simplified example):        var items = new List<string> { apple, dog, chair };        if (items != null && items.Any())        {            foreach (var item in items)            {                Console.WriteLine(item);            }        }Essentially each time we are iterating over a collection we check to make sure the collection is not null and it actually contains at least one item.I decided to write the following extension methods to alleviate this mess (the ML suffix on the methods was to differentiate from Linq [mostly for testing]):        public static class EnumerableExtensions        {            public static IEnumerable<T> AllOrDefaultML<T>(this IEnumerable<T> items)            {                if (items.IsNullML()) return new List<T>();                return items;            }            public static IEnumerable<T> AllOrDefaultML<T>(this IEnumerable<T> items, Func<T, bool> predicate)            {                items = items.AllOrDefaultML();                if (!items.AnyML()) return new List<T>();                return items.Where(predicate);            }            public static IEnumerable<T> EachML<T>(this IEnumerable<T> items, Action<T> fn)            {                var e = items.GetEnumerator();                while (e.MoveNext())                {                    fn(e.Current);                }                return items;            }            public static bool IsNullML(this object item)            {                return item == null;            }            public static bool IsNullOrEmptyML<T>(this IEnumerable<T> items)            {                return !items.AnyML();            }            public static bool AnyML<T>(this IEnumerable<T> items)            {                if (items.IsNullML()) return false;                return items.Count() > 0;            }            public static bool AnyML<T>(this IEnumerable<T> items, Func<T, bool> predicate)            {                if (items == null) return false;                items = items.Where(predicate);                return items.Count() > 0;            }        }Essentially with these methods I can write the above code as the following:        var items = new List<string> { apple, dog, chair };        foreach (var item in items.AllOrDefaultML())        {            Console.WriteLine(item);        }Or even integrate the Each() method:        var items = new List<string> { apple, dog, chair };        items.AllOrDefaultML().EachML(i => Console.WriteLine(i));I'm not sure how I feel about the above, but you get the idea.I've also added a predicate to AllOrDefaultML() which works if the sequence is null:        foreach (var item in items.AllOrDefaultML(i => i.Length == 5))        {            Console.WriteLine(item);        }Linq has a FirstOrDefault() method, why not have an AllOrDefault() which returns you an empty sequence if it's null and doesn't have any items?I'm hoping to get some insight in to the question above, and also wondering if anyone else has implemented anything like this before? Has it cleaned up your code much? Is it easier to read? Is it confusing for colleagues (particularly new start) who aren't totally aware of what's happening? Is there anything fundamentally wrong with what I have here?
IEnumerable Extensions Linq AllOrDefault() Each()
c#;linq;extension methods
Overall, the problem of having a collection, not knowing whether it's null, and wanting to treat a null collection the same as an empty one is probably a problem to be avoided, rather than solved. But that's beyond the scope of this question.Generally this is well-written. You already mentioned the reason for the ML suffix, but to emphasize, it should definitely be removed.For naming in general, I'd steer away from OrDefault for a few reasons:It's already used in FirstOrDefault and SingleOrDefault means default for an element, not a collection, so the connotations are a bit misleadingThe default keyword on a collection type would return null, not an empty collection, so again, the connotations aren't exactly what you want.It's quite cumbersomeSomething as simple as .Safe() for your AllOrDefault method might be more appropriate.Going by LINQ conventions, source is also a more idiomatic name than items.EachML is quite weirdly implemented. Why not just use a foreach loop?Alternatively, if you want to maintain laziness, you could do something like:return items.Select(i =>    {        fn(i);        return i;    });This then wouldn't be evaluated until the collection was enumerated over. However, I think that's probably more confusing/unexpected behaviour than the simple eager foreach.Some of your methods seem a bit redundant. Do you really need a special IsNull method? Do you need IsNullOrEmptyML when you can just negate AnyML? More generally, you can remove both those methods and your overloads which take predicates altogether. Then you can just do, e.g. collection.Safe().Any(predicate) rather than collection.AnyML(predicate). This saves you basically having to reimplement the majority of LINQ methods and just add in an extra null check.So finally, with some radical pruning, I think everything there could be cut down to:public static IEnumerable<T> Safe<T>(IEnumerable<T> source){    return source ?? Enumerable.Empty<T>();}public static void ForEach<T>(IEnumerable<T> source, Action<T> action){    foreach(var item in source)    {        action(source);    }}