C# Interface IEnumerable Any() 没有指定泛型类型
C# Interface IEnumerable Any() without specifying generic types
我投了
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,我也做不到。
如果不指定通用类型,我将如何执行此操作。
一种方法是使用foreach
, as noted in IEnumerable "Remarks"。它还提供了有关 GetEnumerator 结果的其他方法的详细信息。
bool hasAny = false;
foreach (object i in (IEnumerable)(new int[1] /* IEnumerable of any type */)) {
hasAny = true;
break;
}
(它本身很容易转移到扩展方法。)
虽然你不能直接这样做,但你可以通过 Cast
:
if (enumerable.Cast<object>().Any())
这应该总是可行的,因为任何 IEnumerable
都可以包装为 IEnumerable<object>
。如果它是 actually 一个 IEnumerable<int>
或类似的,它最终会装箱第一个元素,但它应该可以正常工作。与大多数 LINQ 方法不同,Cast
和 OfType
目标是 IEnumerable
而不是 IEnumerable<T>
.
当然,您可以编写自己的扩展方法子集,例如 LINQ 方法,但如果您愿意,可以在非泛型 IEnumerable
类型上运行。实施 LINQ to Objects 并不难 - 例如,您可以使用我的 Edulinq project 作为起点。
在某些情况下,您可以比使用 Cast
更有效地实现 Any(IEnumerable)
- 例如,如果目标实现非通用 ICollection
接口,则采取快捷方式。那时,您不需要创建迭代器或获取第一个元素。在大多数情况下,这不会产生太大的性能差异,但如果您正在优化,您 可以 做这种事情。
您尝试使用 GetEnumerator().Current
试图获取尚未移动到第一个位置的枚举器的当前值。如果第一项存在或为空,它也会给出错误的结果。您可以做的(以及 Enumerable
中的 Any()
所做的)是查看是否可以移动到第一项;即是否有第一项要移动到:
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);
}
我投了
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,我也做不到。
如果不指定通用类型,我将如何执行此操作。
一种方法是使用foreach
, as noted in IEnumerable "Remarks"。它还提供了有关 GetEnumerator 结果的其他方法的详细信息。
bool hasAny = false;
foreach (object i in (IEnumerable)(new int[1] /* IEnumerable of any type */)) {
hasAny = true;
break;
}
(它本身很容易转移到扩展方法。)
虽然你不能直接这样做,但你可以通过 Cast
:
if (enumerable.Cast<object>().Any())
这应该总是可行的,因为任何 IEnumerable
都可以包装为 IEnumerable<object>
。如果它是 actually 一个 IEnumerable<int>
或类似的,它最终会装箱第一个元素,但它应该可以正常工作。与大多数 LINQ 方法不同,Cast
和 OfType
目标是 IEnumerable
而不是 IEnumerable<T>
.
当然,您可以编写自己的扩展方法子集,例如 LINQ 方法,但如果您愿意,可以在非泛型 IEnumerable
类型上运行。实施 LINQ to Objects 并不难 - 例如,您可以使用我的 Edulinq project 作为起点。
在某些情况下,您可以比使用 Cast
更有效地实现 Any(IEnumerable)
- 例如,如果目标实现非通用 ICollection
接口,则采取快捷方式。那时,您不需要创建迭代器或获取第一个元素。在大多数情况下,这不会产生太大的性能差异,但如果您正在优化,您 可以 做这种事情。
您尝试使用 GetEnumerator().Current
试图获取尚未移动到第一个位置的枚举器的当前值。如果第一项存在或为空,它也会给出错误的结果。您可以做的(以及 Enumerable
中的 Any()
所做的)是查看是否可以移动到第一项;即是否有第一项要移动到:
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);
}