通常检查null,不会在非约束类型上包含nullables。

假设我有以下方法:

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

我有这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()); 

我写了一个小函数来做一个循环并计算一百万次迭代。 将它应用于intsstrings ,它在我的机器上完成大约100毫秒。 对于nullableInts ,需要2.5秒。 据我所知,在int上检查null是没有意义的,因此编译器为不可为空的struct类型提供了不同的模板,这将删除空检查。 但是Nullable没有将空检查转换为x.HasValue的模板。 如果我有一个无约束的函数,我怎么能做一个表现良好的空检查? 我不能使用EqualityComparer ,因为null可能不是T的成员,因为没有约束。

也不可能有因约束而不同的重载,所以我不能说,有一个用于structs ,一个用于Nullable ,一个用于类。

该方法的调用者是非约束的。 这只是一个例子(不是实际的方法); 调用方法是非约束的。 我需要针对非null成员做一些工作,这是一种通用方法。 我想我可以编写一个不执行检查的版本与执行该版本的版本(因此具有不同的签名),但它看起来非常难看且不需要。

此外,扩展方法.Count莫名其妙地对NullableIntsstrings执行可怕(同样糟糕),所以它真的不是正确的方法。 这可能是委托调用,但我对此表示怀疑。 使用Check.IfNullUnboxT样式方法Check.IfNull执行得更好。 好吧,真的很奇怪切换计数的主体到这个表现很好:

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

为什么?

您可以将generics类型参数约束为引用类型或值类型:

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

对于不可为空的结构,您不需要重载,因为它们无论如何都不能为空。

使用UnboxT方法有效。 但我也想要一些不需要创建静态类型的东西::

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

使用这种方法,一切都表现相同。 Strings表现更差,但并不比其他任何东西差。

虽然不一定比你的方法更好,但它不需要整个类:

 static Dictionary NullChecks = new Dictionary(); public static Func MakeNullCheck() { object obj; Func func; if (NullChecks.TryGetValue(typeof(T), out obj)) return (Func)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>( Expression.Property(param, typeof(T).GetProperty("HasValue")), param).Compile(); } else func = x => false; NullChecks[typeof(T)] = func; return func; }