将字符串转换为IEnumerable<object>

5

我有一个名为propertyValue的对象传递到我的函数中。

我可以假设这是某种类型的IEnumerable,但由于接口合同,我必须将其作为object接受,而不是直接作为IEnumerable

当我尝试将我的值强制转换为IEnumerable<object>,以便获取长度时,我会收到InvalidCastException

var length = ((IEnumerable<object>) propertyValue).Cast<object>().Count();

我遇到了以下异常:

System.InvalidCastException: 无法将类型为“System.String”的对象强制转换为类型“System.Collections.Generic.IEnumerable`1[System.Object]”。

4个回答

7

IEnumerable<T> 接口是协变的,但是协变不适用于值类型。将值类型强制转换为引用类型会改变表示方式 - 值需要被装箱,返回的是对装箱值的引用。将引用类型强制转换不会改变表示方式 - 它仍然是相同的引用,引用相同的对象。

string 是一个 IEnumerable<char>,因此无法转换为 IEnumerable<object>

如其他答案中所述,解决方案是将其转换为非泛型的 IEnumerable

var length = ((IEnumerable) propertyValue).Cast<object>().Count();

3

我已经解决了这个问题,只需将其转换为IEnumerable而不是转换为IEnumerable<object>即可。

var length = ((IEnumerable) propertyValue).Cast<object>().Count();

1
为什么需要使用 Cast<object>()? - Vadim Martynov
1
要使用Count()扩展方法,必须使用泛型IEnumerable<T>。@VadimMartynov - Jakub Lortz
@VadimMartynov 在非泛型类IEnumerable上,没有Count()的扩展方法。要使用该方法,我必须将其转换为某种类型的IEnumerable<T> - James Monger
1
你不应该这样做。实际上,你不应该这样做,因为它会导致 char 类型的装箱问题。 - Vadim Martynov

1

String 实现了 IEnumerable<char> 接口,你可以将其转换为该接口

var length = ((IEnumerable<char>) propertyValue).Count();

对于未知类型的集合,您可以将其转换为IEnumerable,并使用自己的扩展方法手动枚举值。
static class EnumerableExtensions
{
    public static int Count(this IEnumerable source)
    {
        int res = 0;

        foreach (var item in source)
            res++;

        return res;
    }
}

var collection = propertyValue as IEnumerable;
if(collection != null)
{
    var length = collection.Count();
}

使用 Cast() 方法会导致值类型的装箱,对于大型集合可能会有性能问题。


2
由于作者不知道 Enumerable 的类型,这并不总是有效的。 - dryman
@dryman 你说得对,这是我的失误。但是 Cast 操作会导致值类型的装箱。我会更新我的回答。 - Vadim Martynov

0

以下代码应该能够实现你所需的功能

var length = (propertyValue as IEnumerable<object>).Count();      

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接