Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Interface IEnumerable Any() without specifying generic types

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.

like image 876
Ilan Keshet Avatar asked Oct 02 '18 00:10

Ilan Keshet


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.


3 Answers

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.

like image 150
Jon Skeet Avatar answered Oct 13 '22 13:10

Jon Skeet


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.)

like image 44
user2864740 Avatar answered Oct 13 '22 15:10

user2864740


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);
}
like image 1
Jon Hanna Avatar answered Oct 13 '22 14:10

Jon Hanna