Question

So normally if you want to simply check if an IEnumerable<T> has any items in you'd use .Any() instead of .count > 0 - especially when you're hitting things like LINQ-To-Entities and .count may have a heavy performance penalty.

The problem I have is that I'm writing an IValueConverter to change an objects visibility depending on whether or not an enumerable has items or not:

public class CollectionEmptyVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var col = value as ICollection;

        if (col == null) { return Visibility.Collapsed.ToString(); }

        return (col.Count > 0) ? Visibility.Visible.ToString() : Visibility.Collapsed.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

So in this situation I can't use the normal extension methods on an IEnumerable<T> because I can't have a <T> at this time. My current implementation limits me to things that implement ICollection which may not always be desirable.

How can I do this in a more efficient manner? The bare IEnumerable (sans <T>) doesn't have a .Any().

Was it helpful?

Solution

This will work just fine:

public static class ExtensionMethods
{
    public static bool Any(this IEnumerable t) {
        foreach (var o in t)
            return true;
        return false;
    }
}

Benchmarks:

public static class ExtensionMethods
{
    public static bool AnyJR(this IEnumerable t)
    {
        foreach (var o in t)
            return true;
        return false;
    }

    public static bool AnyPhonicUK(this IEnumerable t)
    {
        var e = t.GetEnumerator();
        try {
            return e.MoveNext();
        }
        finally {
            var edisp = e as IDisposable;
            if (edisp != null)
                edisp.Dispose();
        }
    }
}

class Program
{
    static long Test_AnyJR(List<int> l, int n)
    {
        var sw = Stopwatch.StartNew();

        for (int i = 0; i < n; i++) {
            bool any = l.AnyJR();
        }

        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    static long Test_AnyPhonicUK(List<int> l, int n)
    {
        var sw = Stopwatch.StartNew();

        for (int i = 0; i < n; i++) {
            bool any = l.AnyPhonicUK();
        }

        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    static void Main(string[] args)
    {
        var list = new List<int> { 1, 2, 3, 4 };

        int N = 10000000;
        Console.WriteLine("{0} iterations using AnyJR took {1} ms.", N, Test_AnyJR(list, N));
        Console.WriteLine("{0} iterations using AnyPhonicUK took {1} ms.", N, Test_AnyPhonicUK(list, N));

        Console.ReadLine();
    }
}

Results:

10000000 iterations using AnyJR took 484 ms.
10000000 iterations using AnyPhonicUK took 393 ms.

OTHER TIPS

public object Convert(object value, Type targetType, object parameter, string language)
{
    var col = value as ICollection;
    if (col != null)
        return col.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
    var enu = (IEnumerable)value;
    foreach (var obj in enu)
        return true;
    return false;
}

Or (more concise, but probably a hair slower):

public object Convert(object value, Type targetType, object parameter, string language)
{
    var enu = (IEnumerable)value;
    return enu.Cast<object>().Any() ? Visibility.Visible : Visibility.Collapsed;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top