tags:

views:

55

answers:

3

Let say I have the following method::

public static int CountNonNullMembers<T>(this IEnumerable<T> enumerable)
{
    if (enumerable == null) throw new ArgumentNullException("enumerable");
    int count = 0;
    foreach (var x in enumerable)
    {
        if (x != null) count++; 
    }
    return count;
}

And I have these 3 arrays::

var ints = Enumerable.Range(0,10).ToArray();
var nullableInts = Array.ConvertAll(ints,x=>x as int?);
var strings = Array.ConvertAll(ints,x => x.ToString());

I wrote a little func to do a loop and time it for a million iterations. Applying it to ints and strings finishes in about 100 ms on my machine. For nullableInts, it takes 2.5 seconds. As I understand the check for null on int doesn't make sense, so the compiler has a different template for non-nullable struct types, that removes null checks. But Nullable<T> do not have a template that converts the null check to x.HasValue. If I have an unconstrained function how can I do a null check that will perform well? I can't use EqualityComparer<T>, as null might not be a member of T as there is no constraint.

Also it's impossible to have overloads that differ by constrain, so I can't say have one for structs, one for Nullable<T>, and one for classes.

Edit for clarity:

The caller of the method is non-constrained. This is just an example (not the actual method) the method calling is non-constrained. I need to do some work against non-null members, and it's a generic method. I suppose I could write a version that doesn't do the check vs one that does (and consequently has a different signature), but it's seems very ugly and unneeded.

Edit2::

Also, the extension method .Count inexplicably performs horribly for NullableInts and strings, (equally bad) so it really isn't the right approach. This might be the delegate invocation but I doubt it. Using the UnboxT style method of Check<T>.IfNull performs a lot better. Okay really weird switching the body of the count to this performs great::

    public static int CountNonNullMembers<T>(this IEnumerable<T> enumerable)
    {
        return enumerable.Count(Check<T>.IfNull.Invoke);
    }

why?

+1  A: 

You can constrain generic type parameters to reference types or values types:

public static int CountNonNull<T>(this IEnumerable<T> source)
    where T : class
{
    return source.Count(x => x != null);
}

public static int CountNonNull<T>(this IEnumerable<Nullable<T>> source)
    where T : struct
{
    return source.Count(x => x.HasValue);
}

You don't need an overload for non-nullable structs, because they can't be null anyway.

dtb
This doesn't work as the call site is non-constrained. This is just an example (not the actual method) the method calling is non-constrained.
Michael B
+1  A: 

Using the UnboxT approach works. But I'd also like something that doesn't require creating a static type::

public static class Check<T>
{
            public static readonly Predicate<T> IfNull = CreateIfNullDelegate();
            private static bool AlwaysFalse(T obj)
            {
                return false;
            }

            private static bool ForRefType(T obj)
            {
                return object.ReferenceEquals(obj, null);
            }

            private static bool ForNullable<Tu>(Tu? obj) where Tu:struct
            {
                return !obj.HasValue;
            }
            private static Predicate<T> CreateIfNullDelegate()
            {
                if (!typeof(T).IsValueType)
                    return ForRefType;
                else
                {
                    Type underlying;
                    if ((underlying = Nullable.GetUnderlyingType(typeof(T))) != null)
                    {
                        return Delegate.CreateDelegate(
                            typeof(Predicate<T>),
                            typeof(Check<T>)
                                .GetMethod("ForNullable",BindingFlags.NonPublic | BindingFlags.Static)
                                    .MakeGenericMethod(underlying)
                        ) as Predicate<T>;
                    }
                    else
                    {
                        return AlwaysFalse;
                    }
                }
            }
        }

Using this approach everything performs about the same. Strings performs worse, but not so much worse than everything else.

Michael B
A: 

While not necessarily better than your method, it doesn't require a whole class:

static Dictionary<Type, object> NullChecks = new Dictionary<Type, object>();
public static Func<T, bool> MakeNullCheck<T>()
{
    object obj;
    Func<T, bool> func;
    if (NullChecks.TryGetValue(typeof(T), out obj))
        return (Func<T, bool>)obj;
    if (typeof(T).IsClass)
        func = x => x != null;
    else if (Nullable.GetUnderlyingType(typeof(T)) != null)
    {
        var param = Expression.Parameter(typeof(T));
        func = Expression.Lambda<Func<T, bool>>(
            Expression.Property(param, typeof(T).GetProperty("HasValue")), param).Compile();
    }
    else
        func = x => false;
    NullChecks[typeof(T)] = func;
    return func;
}
Gabe
The point was to do this in a way that performs. `OfType<T>` requires casting and doing an if check its really quite bad.
Michael B
How badly does `OfType` perform?
Gabe
Michael: I see your problem now. It's not that the null check is slow, it's that the `int?` values keep getting boxed.
Gabe