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?