Reputation: 604
I have casted
var info = property.Info;
object data = info.GetValue(obj);
...
var enumerable = (IEnumerable)data;
if (enumerable.Any()) ///Does not compile
{
}
if (enumerable.GetEnumerator().Current != null) // Run time error
{
}
and I would like to see if this enumerable has any elements, via using Linq Query Any(). But unfortunately, even with using Linq, I can't.
How would I do this without specifying the generic type.
Upvotes: 9
Views: 4057
Reputation: 113382
Your attempt to use GetEnumerator().Current
tried to get the current value of an enumerator that had not yet been moved to the first position yet. It would also have given the wrong result if the first item existed or was null. What you could have done (and what the Any()
in Enumerable
does) is see if it was possible to move to that first item or not; i.e. is there a first item to move to:
internal static class UntypedLinq
{
public static bool Any(this IEnumerable source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
IEnumerator ator = source.GetEnumerator();
// Unfortunately unlike IEnumerator<T>, IEnumerator does not implement
// IDisposable. (A design flaw fixed when IEnumerator<T> was added).
// We need to test whether disposal is required or not.
if (ator is IDisposable disp)
{
using(disp)
{
return ator.MoveNext();
}
}
return ator.MoveNext();
}
// Not completely necessary. Causes any typed enumerables to be handled by the existing Any
// in Linq via a short method that will be inlined.
public static bool Any<T>(this IEnumerable<T> source) => Enumerable.Any(source);
}
Upvotes: 2
Reputation: 1503290
While you can't do this directly, you could do it via Cast
:
if (enumerable.Cast<object>().Any())
That should always work, as any IEnumerable
can be wrapped as an IEnumerable<object>
. It will end up boxing the first element if it's actually an IEnumerable<int>
or similar, but it should work fine. Unlike most LINQ methods, Cast
and OfType
target IEnumerable
rather than IEnumerable<T>
.
You could write your own subset of extension methods like the LINQ ones but operating on the non-generic IEnumerable
type if you wanted to, of course. Implementing LINQ to Objects isn't terribly hard - you could use my Edulinq project as a starting point, for example.
There are cases where you could implement Any(IEnumerable)
slightly more efficiently than using Cast
- for example, taking a shortcut if the target implements the non-generic ICollection
interface. At that point, you wouldn't need to create an iterator or take the first element. In most cases that won't make much performance difference, but it's the kind of thing you could do if you were optimizing.
Upvotes: 28
Reputation: 61975
One method is to use foreach
, as noted in IEnumerable "Remarks". It also provides details on the additional methods off of the result of GetEnumerator.
bool hasAny = false;
foreach (object i in (IEnumerable)(new int[1] /* IEnumerable of any type */)) {
hasAny = true;
break;
}
(Which is itself easily transferable to an Extension method.)
Upvotes: 2