5

Just want to make simple extension for syntactic sygar :

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));
}

It works perfectly when I work with some collections, but when working with others I get

The call is ambiguous between the following methods or properties: 'PowerOn.ExtensionsBasic.IsNotEmpty(System.Collections.IList)' and 'PowerOn.ExtensionsBasic.IsNotEmpty(System.Collections.Generic.ICollection)'

Is there any canonical solution to this problem ?

No, I don't want to perform a cast before calling this method ;)

Jeff Sternal
  • 47,787
  • 8
  • 93
  • 120
Mose
  • 1,781
  • 3
  • 16
  • 35
  • Can you cite a collection that has this problem, so we can verify our answers? – Marc Gravell Oct 09 '09 at 15:29
  • 1
    Are you sure those are the declarations? The error message seems to suggest it's IList rather than ICollection. – Jon Skeet Oct 09 '09 at 15:32
  • I've run into this problem quite a bit as well, with extension methods for the generic and non-generic versions of IEnumerable, ICollection, and IList. – Rex M Oct 09 '09 at 15:35
  • 2
    Is the second method even necessary? – David Oct 09 '09 at 15:40
  • The second method is necessary if you're dealing with types that implement ICollection but not ICollection. – Jeff Sternal Oct 09 '09 at 15:42
  • 2
    This is particulary needed when working with interfaces (when you do not know the concrete type of the instance you are working with) : ICollection does not implement ICollection... – Mose Oct 12 '09 at 10:18
  • @Marc Gravell: any collection that explicitly implements both interfaces has this problem. I created a new one and auto-implemented them in Visual Studio. Problem was reproduced. – Roman Boiko Nov 24 '09 at 20:40
  • 1
    @Jon Skeet: that's because `List` implements both `ICollection` and `IList`, while `IList` inherits `ICollection`. So `List` implements both `ICollection` and `ICollection`. – Roman Boiko Nov 24 '09 at 20:45

2 Answers2

4

It's because some collections implements both interfaces, You should convert collection to concrete interface like this

((ICollection)myList).IsNotEmpty();

Or

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

And yea, you will get NullReferanceException if obj == null so you can remove null check ;) which mean that your extension method just compares Count whith 0 which you can do without extension method ;)

Arsen Mkrtchyan
  • 49,896
  • 32
  • 148
  • 184
  • *All* of the generic versions implement their non-generic counterparts, so any generic class would have both. – Rex M Oct 09 '09 at 15:37
  • 1
    Like I said in the last sentence of my question, I don't want to perform a cast before the call. This is for SYNTACTIC SUGAR, if I need to add a cast, then it's definitely useless :p My question remains : any way to solve ambiguity to work on all collections ? – Mose Oct 12 '09 at 08:06
  • 2
    @ArsenMkrt: extension methods can be called on variables with `value == null`, exception will not occur – Roman Boiko Nov 24 '09 at 20:34
  • @Rex M: did you mean all generic classes from .NET Framework implement non-generic interfaces? Is there any link to documentation? – Roman Boiko Nov 24 '09 at 20:36
4

My best way to solve the ambiguity : define an overload for all common non-generic ICollection classes. That means custom ICollection won't be compatible, but it's no big deal as generics are becoming the norme.

Here is the whole code :

/// <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));
}

Note that I did not want it to work on IEnumerable<T>, because Count() is a method that can trigger a database request if you are working with Linq-to-Entity or Linq-to-SQL.

Mose
  • 1,781
  • 3
  • 16
  • 35
  • 2
    After a few weeks using it, it is DEFINITELY the best solution, we mass-adopted it here. – Mose Nov 26 '09 at 10:47