我试图创建一个通用的参数验证方法来检查null,empty或的集合参数是否包含null元素。
public void Foo(ICollection<MyType> bar)
{
// Validate parameters
ThrowIfNullEmptyOrContainsNull(bar, "bar");
.
.
.
如果我只在类型约束中指定ICollection<T>
,则if (value.Contains(null))
会生成错误,因为T
可能不是可空类型。
这就是我想出来的,但它似乎并不正确:
internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
where T1 : ICollection<T2>
where T2 : class
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException(name);
if (value.Count == 0)
throw new ArgumentException("Empty collection not allowed", name);
if (value.Contains(null))
throw new ArgumentException("Collection contains one or more null elements", name);
return value;
}
...但是我必须使用显式参数类型调用该方法,如下所示:
public void Foo(ICollection<MyType> bar)
{
// Validate parameters
ThrowIfNullEmptyOrContainsNull<(ICollection<MyType>, MyType>(bar, "bar");
.
.
.
如果没有在调用中明确指定T1和T2,我会收到错误&#34;类型参数...无法从使用情况中推断出来。&#34;。
有人能说清楚如何做到这一点吗?
答案 0 :(得分:2)
不要使用Contains
。迭代整个集合并明确地将值与null
进行比较:
internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
where T1 : ICollection<T2>
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException(name);
if (value.Count == 0)
throw new ArgumentException("Empty collection not allowed", name);
foreach (var item in value)
if (item == null)
throw new ArgumentException("Collection contains one or more null elements", name);
return value;
}
答案 1 :(得分:2)
如下:
if (value.Any(item => item == null))
{
throw new ArgumentException("Collection contains one or more null elements", name);
}
如:
internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
where T1 : ICollection<T2>
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException(name);
if (value.Count == 0)
throw new ArgumentException("Empty collection not allowed", name);
if (value.Any(item => item == null))
throw new ArgumentException("Collection contains 1 or more null items", name);
return value;
}
答案 2 :(得分:1)
扩展方法怎么样?根据需要包含异常或消息
public static bool IsNullOrEmpty<T>(this ICollection<T> alist) where T:class
{
if (alist == null || alist.Count == 0){
return true;
}
if (alist.Any(t => t == null)) {
return true;
}
return false;
}
使用:强>
if ( myList.IsNullOrEmpty ) {
//.. exception, error handling
}
无需传递MyList的类型,因为MyList必须实现ICollection 可能对您有用,无需通过类型要求 添加T:Class to suggestion。但你已经知道了: - )
答案 3 :(得分:1)
我们可以将非可空类型与null进行比较,因为所有对象都可以转换为object
并进行比较:
bool obviouslyFalse = 1 == null;
这将导致警告,但有效。显然它始终是false
,实际上编译器会通过删除比较来优化,并为我们提供等价物,就像我们有bool obviouslyFalse = false;
一样。
使用泛型同样适用于:
T item = getTFromSomewhere;
bool obviouslyFalseIfTIsntNullable = item == null;
然后这对所有可能的T
都有效,虽然编译器无法删除比较,但抖动可以,实际上也是。
internal static TCol ThrowIfNullEmptyOrContainsNull<TCol, TEl>(TCol collection, string name)
where TCol : ICollection<TEl>
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException(name);
if (value.Count == 0)
throw new ArgumentException("Empty collection not allowed", name);
foreach(var item in collection)
if(item == null)
throw new ArgumentException("Collection cannot contain null elements", name);
return value;
}
这样可行,但如果我们有大量非可空类型,那就太浪费了;抖动不太可能删除该迭代,即使它什么都不做,所以它仍然会得到一个枚举器并在其上调用MoveNext()
,直到它返回false。我们可以帮助它:
internal static TCol ThrowIfNullEmptyOrContainsNull<TCol, TEl>(TCol collection, string name)
where TCol : ICollection<TEl>
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException(name);
if (value.Count == 0)
throw new ArgumentException("Empty collection not allowed", name);
if(default(TEl) == null)
foreach(var item in collection)
if(item == null)
throw new ArgumentException("Collection cannot contain null elements", name);
return value;
}
因为default(TEl) == null
对于可空类型(包括Nullable<T>
)始终为true,对于非可空类型始终为false,因此将通过删除所有类型的比较来优化抖动,并删除整个枚举对于非可空类型。因此,立即可以通过该方法获得大量的整数(例如)。