All posts

LINQ: Sequence contains no elements. Extension methods to the rescue

When you start playing with LINQ queries over sequences of elements (e.g. getting min / max value for enumerable source) sooner or later you will come across this one -- the InvalidOperationException (“Sequence contains no elements”).

The problem occurs as by default queries like IEnumerable<T>.Min(…) and IEnumerable<T>.Max(…) do not play nicely if you try to execute them on an empty sequence and just throw the exception described above. Unfortunately these methods do not have a corresponding counterpart like Single(…) / SingleOrDefault(…) that is smart enough to query the sequence if it is not empty or alternatively use the default value without raising an exception.

Basically you got two options now:

  • Either perform the check on the enumerable sequence every time you are querying it
  • OR integrate the logic in an extension method.

The second approach is much preferable so let’s add the missing link below:

namespace ExtensionMethods
{
   
using System;
   
using System.Collections.Generic;
   
using System.Linq;

   
public static class IEnumerableExtensions
   
{
       
/// <summary>
        /// Invokes a transform function on each element of a sequence and returns the minimum Double value 
        /// if the sequence is not empty; otherwise returns the specified default value. 
        /// </summary>
        /// <typeparam name="TSource">The type of the elements of source.</typeparam>
        /// <param name="source">A sequence of values to determine the minimum value of.</param>
        /// <param name="selector">A transform function to apply to each element.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The minimum value in the sequence or default value if sequence is empty.</returns>
        public static double MinOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector, double defaultValue)
       
{
           
if (source.Any<TSource>())
               
return source.Min<TSource>(selector); 

           
return defaultValue;
       
}

       
/// <summary>
        /// Invokes a transform function on each element of a sequence and returns the maximum Double value 
        /// if the sequence is not empty; otherwise returns the specified default value. 
        /// </summary>
        /// <typeparam name="TSource">The type of the elements of source.</typeparam>
        /// <param name="source">A sequence of values to determine the maximum value of.</param>
        /// <param name="selector">A transform function to apply to each element.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The maximum value in the sequence or default value if sequence is empty.</returns>
        public static double MaxOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector, double defaultValue)
       
{
           
if (source.Any<TSource>())
               
return source.Max<TSource>(selector); 

           
return defaultValue;
       
}
   
}
}
 
Now you only need to add the using ExtensionMethods; directive in your project and you are all set:
 extensionmethods
 
 
Hope this helps.

Facebook Twitter DZone It! Digg It! StumbleUpon Technorati Del.icio.us NewsVine Reddit Blinklist Add diigo bookmark

Comments  9

  • 18 Oct

    Thanks, just what I needed! Got this error recently while using First() on the IEnumerable.

    Loki

  • 28 Oct

    Hey, this is really inefficient. Imagine a sequence with 100,000 elements - you have to enumerate over each of those to evaluate the Count(). Use the Any() extension method instead, it only has to enumerate over the first element.

    Mike

  • 31 Oct

    Mike thanks for the suggestion! Indeed it would be a nice optimization and I've updated the source to use Any() instead of Count() calls.

    Manol Donev

  • 12 Nov

    good

    panlin

  • 05 Dec

    Would this be suitable for getting the max value from a database field? Or is there another way to do this? I want to make sure that it is taking advantage of the DBMS MAX(), so the client doesn't have to download all the records just to find the maximum.But it also has to handle the possible NULL that MAX() can return...

    Any ideas?

    Tony

  • 29 Mar

    I found this post by googling for the same problem. I was about to use the solution here when I discovered extension method System.Data.Enumerable.DefaultIfEmpty. That will do the same thing, I think, as what you suggest here....

    Jon

  • 07 May

    A generic implementation with some overloads:

    public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source) { return source.MaxOrDefault<TSource, TSource>(s => s); } 
    public static TSource MaxOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue) { return source.MaxOrDefault<TSource, TSource>(s => s, defaultValue); } 
    public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) { return source.MaxOrDefault(selector, default(TResult)); } 
    public static TResult MaxOrDefault<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, TResult defaultValue) { return source.Any() ? source.Max(selector) : defaultValue; }  

    Really easy to implement also the MinOrDefault, just change the methods names and the Max() in Min().

    Aquilax

  • 15 Jun

    Thanks man, that was what I need :-)

    Chavdar

  • 15 Sep

    Hi,

    I'm having some trouble using RadControls_for_WPF_2009_2_0813_TRIAL. I have used in a project RadWindow for WPF. "Sometimes" when I close a window the InvalidOperationException is thrown. I'm hoping to find help here, because for the moment I'm using the trial version of the controls, trying to demonstrate that this is a fine acquisition. Here is part of my stack trace:

    Startup URI: ....xbap
    Application Identity: file:///....xbap

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Sequence contains no elements
       at System.Linq.Enumerable.Max(IEnumerable`1 source)
       at Telerik.Windows.Controls.RadWindowPopup.WindowPopupAdornerFactory.WindowPopupAdornerImpl.BringToFront()
       at Telerik.Windows.Controls.RadWindowManager.BringToFront(RadWindow window)
       at Telerik.Windows.Controls.RadWindow.<BringToFront>b__3()
       --- End of inner exception stack trace ---
       at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Delegate.DynamicInvokeImpl(Object[] args)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.Run()
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.StartDispatcherInBrowser(Object unused)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

    -----------------------

    Thanks !!

    Dan

Post a comment
  1. Formatting options
       
     
     
     
     
       
  2. Security image