如何使用反射将运行时类型 A: IList<AT> 的集合转换为类型 B: IList<BT> 的新集合?

How to transform collection with runtime type A: IList<AT> into a new collection of type B: IList<BT> using reflection?

在编译时对类型一无所知。

object TransformObject(object oldObject, Type newType, Func<object, object> transform)
{
    if(obj.GetType().ImplementsGenericInterface(typeof(IList<>))
    && newType.ImplementsGenericInterface(typeof(IList<>)))
    {
        object newCollection = Activator.CreateInstance(newType);

        // This is where it gets tricky:
        // 1. How to iterate over the old collection?
        // 2. How to add each element in the new collection?
        object oldCollection = oldObject as IEnumerable;
        foreach(var oldItem in oldCollection)
        {
            object newItem = transform(oldItem);
            newCollection.Add(newItem);
        }

        // 3. How to ensure that the order in the new collection is preserved?

        return newCollection;
    }

    return null;
}

这自然不行

运行 时已知的信息:

试试这个解决方案:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;


public class Test
{
    static bool ImplementsGenericInterface(Type type, Type genericInterface)
    {
        return type.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == genericInterface);
    }

    static object TransformObject(object oldObject, Type newType, Func<object, object> transform)
    {
        if (ImplementsGenericInterface(oldObject.GetType(), typeof(IList<>))
           && ImplementsGenericInterface(newType, typeof(IList<>)))
        {
            object newCollection = Activator.CreateInstance(newType);
            var method = newType.GetMethod("Add");

            foreach (var item in (IEnumerable)oldObject)
            {
                var newItem = transform(item);
                method.Invoke(newCollection, new object[] { newItem });
            }

            return newCollection;
        }

        return null;
    }

    public static void Main()
    {
        var list1 = new List<int>() { 1, 2, 3 };

        var list2 = (List<string>)TransformObject(list1, typeof(List<string>), o => o.ToString());

        foreach (var item in list2)
            Console.WriteLine(item);

        Console.ReadKey();
    }
}