17

我正在尝试使用 Reflection 并遇到以下情况。

在下面的代码中,我们假设 'obj' 的类型可以是IEnumerable<>orICollection<>IList<>

我想将此 System.Object 强制转换为IEnumerable<>始终(作为ICollection<>IList<>继承自IEnumerable<>),以便我想枚举集合并使用反射来编写各个项目。

这背后的动机是我只是想看看序列化器通常如何序列化数据,所以我试图模拟这种情况,希望也能理解反射。

我想过将对象转换为非通用 IEnumerable,但认为这会导致不必要的对象装箱,当我们说IEnumerable<int>...的实际实例时,我想对了吗?

private void WriteGenericCollection(object obj)
    {
        Type innerType = obj.GetType().GetGenericArguments()[0];

        //Example: IEnumerable<int> or IEnumerable<Customer>
        Type generatedType = typeof(IEnumerable<>).MakeGenericType(innerType);

        //how could i enumerate over the individual items?
    }
4

2 回答 2

24

好吧,由于直到运行时您才知道项目的实际类型,因此您不需要使用通用IEnumerable<T>接口;只需使用非通用的,IEnumerable(通用的继承自它):

private void WriteGenericCollection(object obj)
{
    IEnumerable enumerable = (IEnumerable)obj;
    foreach(object item in enumerable)
    {
        ...
    }
}
于 2012-08-29T00:19:33.773 回答
4

你的问题充满了误解。让我们把它们清理干净。

在下面的代码中,我们假设 'obj' 的类型可以是 IEnumerable<>orICollection<>IList<>

如果这是真的,并且如果您知道可枚举的类型,那么编写该方法的更好方法是

private void WriteGenericCollection<T>(IEnumerable<T> obj)
{
    // ...
}

我想始终将此 System.Object 向下转换为 IEnumerable<> (因为 ICollection<> 和 IList<> 无论如何都从 IEnumerable<> 继承),因此我想枚举集合并使用反射来编写各个项目。

在谈论接口时,“继承”不是一个正确的术语;它也可能给你错误的想法。最好将接口视为契约:在考虑实现接口时,您只能决定按照作者的意图实现它或根本不实现它。

一些接口是其他接口的超集;他们的合同说“除了合同规定的其他内容外,实施者还必须这样做。但是从来没有像继承中常见的那样共享实现,因为接口没有任何共享。

“向下转型”也不是您在该方法中所做的正确术语。向下转换意味着转换为更派生的类;还有一个接口:

// Note: the method is still generic!
private void WriteGenericCollection<T>(object obj)
{
    var casted = (IEnumerable<T>)obj;
}

我想过将对象向下转换为非通用 IEnumerable,但认为这会导致不必要的对象装箱,当我们说 IEnumerable 的实际实例时......我想对了吗?

当且仅当IEnumerable<T>对象是T类型(数值类型、a bool、anenum或 a struct)时,才会发生装箱。如果该对象IEnumerable<T>为某些已知对象实现,T那么您可以简单地将其转换为该对象。如果T未知,则转换为非泛型IEnumerable并承受可能的性能损失(无论如何都无法绕过它)。

如果您对对象一无所知,则只需要使用反射(当然,在这种情况下,您还需要为无法枚举的对象制定计划,否则为什么首先允许将它们传递给您的方法?)。

于 2012-08-29T00:18:36.947 回答