4

Personally, I'm a fan of the fluent interface syntax of the IEnumerable/List extension methods in C#, as a client. That is, I prefer syntax like this:

    public void AddTheseGuysToSomeLocal(IEnumerable<int> values)
    {
        values.ToList().ForEach(v => _someLocal += v);
    }

as opposed to a control structure like a foreach loop. I find that easier to process mentally, at a glance. Problem with this is that my code here is going to generate null reference exceptions if clients pass me a null argument.

Let's assume that I don't want to consider a null enumeration to be exceptional -- I want that to result in leaving some local as-is -- I would add a null guard. But, that's a little syntactically noisy for my taste, and that noise adds up in cases where you're chaining these together in a fluent interface and the interim results can be null as well.

So, I created a class called SafeEnumerableExtensions that offers a no-throw guarantee by treating nulls as empty enumerables (lists). Example methods include:

    //null.ToList() returns empty list
    public static List<T> SafeToList<T>(this IEnumerable<T> source)
    {
        return (source ?? new List<T>()).ToList();
    }

    //x.SafeForEach(y) is a no-op for null x or null y
    //This is a shortcut that should probably go in a class called SafeListExtensions later
    public static void SafeForEach<T>(this List<T> source, Action<T> action)
    {
        var myAction = action ?? new Action<T>(t => { });
        var mySource = source ?? new List<T>();
        mySource.ForEach(myAction);
    }

    public static void SafeForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        SafeToList(source).SafeForEach(action);            
    }

Now, my original method is prettier than if there were a null guard, but just as safe, since null result in a no-op:

    public void AddTheseGuysToSomeLocal(IEnumerable<int> values)
    {
        values.ForEach(v => _someLocal += v);
    }

So, my question is twofold. (1) I'm assuming that I'm not so original as to be the first person ever to have thought of this -- does anyone know if there is an existing library that does this or something similar? And (2) has anyone used said library or implemented a scheme like this and experienced unpleasant consequences or else can anyone foresee unpleasant consequences for doing something like this? Is this even a good idea?

(I did find this question when checking for duplicates, but I don't want to explicitly do this check in clients - I want the extension class to do this implicitly and not bother clients with that extra method call)

Community
  • 1
  • 1
Erik Dietrich
  • 6,080
  • 6
  • 26
  • 37
  • I'm going to pass you a very, very long sequence. You're going to walk over the entire sequence just so you can use a method versus a standard loop? And *then* you're going to walk over the entire sequence once again to do the actual work? – Anthony Pegram Dec 04 '11 at 00:24
  • @AnthonyPegram I think he's only talking about checking whether the list reference you passed *is null* not whether the referenced list *contains nulls* – phoog Dec 04 '11 at 00:28
  • 1
    @phoog, you're not passing a list. You're passing an IEnumerable. He's invoking ToList, which walks the entire sequence, simply so he can use a method which arguably is no more expressive or succinct than just the regular old loop, and then (of course) he will walk the sequence again (in the method). Regarding the null check, I took that part out of my comment for its redundancy, but regardless, I'm well aware he was talking about the sequence reference. – Anthony Pegram Dec 04 '11 at 00:40
  • This is On Error Goto Next programming. Much easier to get done in visual basic. – Hans Passant Dec 04 '11 at 00:53
  • @Anthony, it depends on the context and, among other things, my willingness to trade performance for expressiveness (as I see it). The example in question was just something I threw up off the top of my head to illustrate the fluent interface chaining of that set of extension methods and the possibility for null, and not necessarily reflective of an actual, example usage of the set of methods that I have in mind. – Erik Dietrich Dec 04 '11 at 01:10
  • @AnthonyPegram, too late to edit my previous comment, but I should also mention, point taken about the performance consideration. That is, my example client code was for example purposes, but the shortcut method is a bad idea, since it's hiding the bad performance from clients behind an easy-to-use interface. If they want to do that, it should be on them. – Erik Dietrich Dec 04 '11 at 01:27

1 Answers1

7

And (2) has anyone used said library or implemented a scheme like this and experienced unpleasant consequences or else can anyone foresee unpleasant consequences for doing something like this? Is this even a good idea?

Personally I would consider this a bad idea. In most cases passing a null enumeration or null Func is probably not intended.

You are "fixing" the problem which might lead to seemingly unrelated problems later down the road. Instead I would rather throw an exception in this case so that you find this problem in your code early on ("Fail fast").

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • That's a good point. In the specific example method that I posted, passing in a null to that method wouldn't make any sense. But, I'm wondering if there are more nuanced examples where the fail fast notion wasn't as clear. – Erik Dietrich Dec 04 '11 at 00:20
  • I'm going to accept this answer, since it seems to be the main issue that I ought to consider in looking at this practice -- whether I'm helping clients mask problems or not. Thanks for your input. – Erik Dietrich Dec 04 '11 at 02:50