首页 > 解决方案 > 如何将未知类型的 IList(类型在运行时已知)转换为数组?

问题描述

我正在使用反射在运行时复制任何自定义类的对象。我FieldInfo用来获取所有字段,然后根据它们的类型正确复制它们。

在复制算法开始时我可以使用的唯一类型是System.Object(AKA object)。我做了很多类型检查。所以当我的检查方法说这个特定的对象是一些简单的一维数组时,它是数组,毫无疑问。但是,我只能在运行时访问该数组中的元素类型。

我确实成功复制List<type known at runtime>了这样的:

public object Get_ListCopy(object original)
{
    Type elementType = original.GetType().GetGenericArguments()[0];
    Type listType = typeof(List<>).MakeGenericType(elementType);

    object copy = Activator.CreateInstance(listType);
    var copyIList = copy as IList;

    foreach (var item in original as IEnumerable)
        copyIList.Add(item);

    copy = copyIList;

    return copy;
}

然后我尝试重新编写简单数组的方法:

public object Get_ArrayCopy(object original)
{
    Type elementType = original.GetType().GetElementType();    // difference here
    Type listType = typeof(List<>).MakeGenericType(elementType);

    object copy = Activator.CreateInstance(listType);
    var copyIList = copy as IList;

    foreach (var item in original as IEnumerable)
        copyIList.Add(item);

    copy = Enumerable.Range(0, copyIList.Count).Select(i => copyIList[i]).ToArray();    // difference here

    return copy;
}

但是在使用以下方法为字段赋值时会返回异常FieldInfo.SetValue(copyObject, convertedValue) // where convertedValue is object copy from the method above

System.ArgumentException: 'Object of type 'System.Object[]' cannot be converted to type 'System.Int32[]'.'

对于该特定示例,数组如下所示:

public int[] Array = { 1, 2, 3 };

最后一件事:我知道如何使用泛型方法解决这个问题MethodInfo ...MakeGenericMethod(...).Invoke,我只是认为可以避免(也许我错了)。也不能使用序列化。

标签: c#reflectiontype-conversion

解决方案


你的线

copy = Enumerable.Range(0, copyIList.Count)
    .Select(i => copyIList[i])
    .ToArray();

实际上是:

copy = Enumerable.Range(0, copyIList.Count)
    .Select<int, object>(i => copyIList[i])
    .ToArray<object>();

编译器知道这copyIList是一个 IList。当您这样做时copyIList[i],您访问IList 的索引器,该索引器返回object. 所以Select返回一个IEnumerable<object>ToArray()因此生成一个object[]

Array 有一个Clone 方法,可以让你的生活更轻松:

((Array)original).Clone();

如果做不到这一点,您可以使用Array.CreateInstance.


对于 List 情况,使用 List 的构造函数会更容易,它需要另一个列表来复制:

public object Get_ListCopy(object original)
{
    Type elementType = original.GetType().GetGenericArguments()[0];
    Type listType = typeof(List<>).MakeGenericType(elementType);

    object copy = Activator.CreateInstance(listType, new[] { original });
    return copy;
}

推荐阅读