How to convert IList of unknown type (type is known at runtime) to array?

牧云@^-^@ 提交于 2020-02-23 07:24:50

问题


I am using reflection to copy an object of any custom class at runtime. I am using FieldInfo to get all the fields and then properly copy them based on their type.

Only type I can work with at the start of the copy algorithm is System.Object (AKA object). I do a lot of type checking. So when my check method says this particular object is some simple one-dimensional array, it is array, no doubt. However I can access the type of elements in that array only at runtime.

I did successfully copied List<type known at runtime> like this:

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

Then I tried to re-write the method for simple array:

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

But that returns an exception when assigning value to field using 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[]'.'

For that particular example the array looked like this:

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

One last thing: I know how to solve this problem using generic methods and MethodInfo ...MakeGenericMethod(...).Invoke , I just thought it could be avoided(maybe I am wrong). Also serialization can't be used.


回答1:


Your line

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

Is actually:

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

The compiler knows that copyIList is an IList. When you do copyIList[i], you access IList's indexer, which returns object. So the Select returns an IEnumerable<object>, and the ToArray() therefore generates an object[].

Array has a Clone method which will make your life easier:

((Array)original).Clone();

Failing that, you can instantiate a new array with Array.CreateInstance.


For the List case, it would be easier to use List's constructor which takes another list to copy:

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


来源:https://stackoverflow.com/questions/58475741/how-to-convert-ilist-of-unknown-type-type-is-known-at-runtime-to-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!