Интерфейс C # IEnumerable Any () без указания универсальных типов - PullRequest
0 голосов
/ 02 октября 2018

Я произнесла

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
{
}

, и я хотел бы посмотреть, есть ли в этом перечислимом какие-либо элементы, с помощью Linq Query Any ().Но, к сожалению, даже с использованием Linq я не могу.

Как бы я это сделал без указания универсального типа.

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

Хотя вы не можете сделать это напрямую, вы можете сделать это через Cast:

if (enumerable.Cast<object>().Any())

Это должно работать всегда, так как любой IEnumerable может быть заключен в IEnumerable<object>.Это закончится тем, что будет упакован первый элемент, если он на самом деле или IEnumerable<int> или аналогичный, но он должен работать нормально.В отличие от большинства методов LINQ, Cast и OfType target IEnumerable, а не IEnumerable<T>.

Вы можете написать собственное подмножество методов расширения, таких как LINQ, но работающих на неуниверсальных IEnumerable Напечатайте, если хотите, конечно.Реализация LINQ to Objects не очень сложна - вы можете использовать мой Edulinq проект , например, в качестве отправной точки.

В некоторых случаях вы могли бы реализовать Any(IEnumerable) чуть более эффективно, чемиспользование Cast - например, использование ярлыка, если цель реализует неуниверсальный интерфейс ICollection.На этом этапе вам не нужно создавать итератор или брать первый элемент.В большинстве случаев это не будет иметь большого значения для производительности, но это то, что вы могли бы сделать, если бы оптимизировали.

0 голосов
/ 10 октября 2018

Ваша попытка использовать GetEnumerator().Current пыталась получить текущее значение перечислителя, который еще не был перемещен в первую позицию.Это также дало бы неправильный результат, если бы первый элемент существовал или был нулевым.Что вы могли бы сделать (и что делает Any() в Enumerable), так это посмотреть, можно ли было перейти к этому первому предмету или нет;то есть есть ли первый элемент для перемещения:

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);
}
0 голосов
/ 02 октября 2018

Одним из методов является использование foreach, как отмечено в IEnumerable "Замечания" .Он также предоставляет подробную информацию о дополнительных методах результата GetEnumerator.

bool hasAny = false;
foreach (object i in (IEnumerable)(new int[1] /* IEnumerable of any type */)) {
    hasAny = true;
    break;
}

(который сам по себе легко переносится в метод Extension.)

...