【问题标题】:How to convert IList of unknown type (type is known at runtime) to array?如何将未知类型的 IList(类型在运行时已知)转换为数组?
【发布时间】:2019-10-20 17:59:08
【问题描述】:

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

我可以在复制算法开始时使用的唯一类型是System.Object(又名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 来解决这个问题,我只是认为可以避免(也许我错了)。也不能使用序列化。

【问题讨论】:

  • 为什么不直接打电话给ToArray copyList
  • @HimBromBeere IList 没有 ToArray 方法。

标签: c# reflection type-conversion


【解决方案1】:

你的线路

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's indexer,它返回object。所以Select 返回一个IEnumerable&lt;object&gt;ToArray() 因此生成一个object[]

Array 有一个Clone method,这将使您的生活更轻松:

((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;
}

【讨论】:

  • 值得注意的是,数组本身将被深度复制,但该数组中的项目将被浅复制。我用通用方法调用解决了完整的深度复制。我在这里提出了另一个关于深拷贝的问题:link 如果你想看的话。顺便说一句,谢谢。
  • @sanitizedUser 是的,与您问题中的代码相同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多