ICollection / ICollection<T> 歧义问题

5

我只想为 语法糖 制作一个简单的扩展:

public static bool IsNotEmpty(this ICollection obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}

public static bool IsNotEmpty<T>(this ICollection<T> obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}

当我使用一些集合时,它可以完美地工作,但是当我使用其他集合时,会出现以下错误:

调用以下方法或属性时存在歧义: 'PowerOn.ExtensionsBasic.IsNotEmpty(System.Collections.IList)' 和 'PowerOn.ExtensionsBasic.IsNotEmpty(System.Collections.Generic.ICollection)'

有没有解决这个问题的标准方法?

不,我不想在调用此方法之前执行转换;)


1
你确定那些是声明吗?错误信息似乎表明它是IList而不是ICollection。 - Jon Skeet
2
第二种方法是否必要? - David
2
这在使用接口时尤其需要(当您不知道正在使用的实例的具体类型时):ICollection<T>没有实现ICollection... - Mose
@Marc Gravell:任何明确实现这两个接口的集合都有这个问题。我在Visual Studio中创建了一个新的集合并自动实现了它们,但问题仍然存在。 - Roman Boiko
1
@Jon Skeet:这是因为List<T>实现了ICollectionIList<T>,而IList<T>继承了ICollection<T>。因此,List<T>同时实现了ICollectionICollection<T> - Roman Boiko
显示剩余3条评论
2个回答

4

这是因为一些集合实现了两个接口,你应该将集合转换为具体的接口,像这样:

((ICollection)myList).IsNotEmpty();

或者

((ICollection<int>)myIntList).IsNotEmpty();

如果 obj == null,你会得到 NullReferanceException,因此你可以删除null检查; 这意味着你的扩展方法只是比较 Count 和 0,这可以在没有扩展方法的情况下完成;)


所有泛型版本都实现了它们的非泛型对应版本,因此任何泛型类都将同时拥有两者。 - Rex M
1
正如我在问题的最后一句话中所说,我不想在调用之前执行强制类型转换。这是为了语法糖,如果需要添加强制类型转换,则肯定没有意义:p我的问题仍然存在:有没有办法解决歧义以适用于所有集合? - Mose
2
@ArsenMkrt:扩展方法可以在value == null的变量上调用,不会发生异常。 - Roman Boiko
@Rex M:你是说.NET Framework中的所有泛型类都实现了非泛型接口吗?有没有相关文档链接? - Roman Boiko

4

我解决歧义的最佳方式是:为所有常见的非泛型ICollection类定义一个重载。 这意味着自定义ICollection将不兼容,但这并不重要,因为泛型正在成为常态。

以下是完整代码:

/// <summary>
/// Check the given array is empty or not
/// </summary>
public static bool IsNotEmpty(this Array obj)
{
    return ((obj != null)
        && (obj.Length > 0));
}
/// <summary>
/// Check the given ArrayList is empty or not
/// </summary>
public static bool IsNotEmpty(this ArrayList obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given BitArray is empty or not
/// </summary>
public static bool IsNotEmpty(this BitArray obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given CollectionBase is empty or not
/// </summary>
public static bool IsNotEmpty(this CollectionBase obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given DictionaryBase is empty or not
/// </summary>
public static bool IsNotEmpty(this DictionaryBase obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given Hashtable is empty or not
/// </summary>
public static bool IsNotEmpty(this Hashtable obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given Queue is empty or not
/// </summary>
public static bool IsNotEmpty(this Queue obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given ReadOnlyCollectionBase is empty or not
/// </summary>
public static bool IsNotEmpty(this ReadOnlyCollectionBase obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given SortedList is empty or not
/// </summary>
public static bool IsNotEmpty(this SortedList obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given Stack is empty or not
/// </summary>
public static bool IsNotEmpty(this Stack obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}
/// <summary>
/// Check the given generic is empty or not
/// </summary>
public static bool IsNotEmpty<T>(this ICollection<T> obj)
{
    return ((obj != null)
        && (obj.Count > 0));
}

请注意,我不想让它适用于 IEnumerable<T>,因为Count()是一个方法,如果你正在使用 Linq-to-Entity 或 Linq-to-SQL,它可能会触发一个数据库请求。

2
使用了几周后,它绝对是最好的解决方案,我们在这里大规模采用了它。 - Mose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接