使用反射将Cast List<object>转换为未知类型T[]

4

我在另一个问题中找到了类似的内容,但由于我对C#还很陌生,所以无法解决我的问题。

我有如下代码:

System.Type type; // for example int[]
System.Type elementType = type.GetElementType(); //for example int

我需要将一个列表强制转换为int[]类型

object valueObj; //is my List<object> i want to cast to int[]

我正在尝试以下操作:

MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast")
    .MakeGenericMethod( new System.Type[]{ elementType } );
MethodInfo toArrayMethod = typeof(Enumerable).GetMethod("ToArray")
     .MakeGenericMethod( new System.Type[]{ elementType } );

var castedObjectEnum = castMethod.Invoke(null, new object[] { valueObj });
var castedObject = toArrayMethod.Invoke(null, new object[] { castedObjectEnum });

在最后一行,我遇到了这个运行时异常:
InvalidCastException: 无法将源类型转换为目标类型。 System.Linq.Enumerable+c__Iterator01[System.Int32].MoveNext () System.Collections.Generic.List1[System.Int32].AddEnumerable (IEnumerable`1 enumerable)
最后,我需要使用以下方式将castObject赋值给privateField:
field.SetValue(this, castedObject);

编辑:

我会尝试获取更多信息,但为了更好地解释我的目的,我将解释使用情况。

我将一些类字段序列化到磁盘中的json文件中,然后当我反序列化时,我会得到一个List,其中我会序列化一个基本的int/bools/string数组。

我通过使用自定义属性标记字段来进行序列化和反序列化,并且我希望能够序列化任何基本类型的Array和List。

我会再次检查并提供更多信息。


2
请不要只张贴“代码片段”,而是将其整合到一个短但完整的控制台应用程序中,以演示问题。这将使其他人帮助您变得容易得多 - Jon Skeet
它们实际上都是int类型吗?它们是否可以转换为int类型?为什么你在代码的这个点上不知道实际类型?反射应该很少需要,因此所有这些答案都将有助于回答您的问题。 - user7116
我不知道类型,我在使用案例上添加了一点解释。@jonSkeet,我会再次检查并尝试隔离问题。 - Ultrakorne
2个回答

4
我不知道你做错了什么。
这里有一个LINQPad程序(http://linqpad.net),演示了这个过程,它似乎使用了与你相同的调用,但我确实获得了正确类型数组的输出。
void Main()
{
    object valueObj = new List<object> { 1, 2, 3 };
    Type type = typeof(int[]);

    Type elementType = type.GetElementType();
    MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast")
        .MakeGenericMethod( new System.Type[]{ elementType } );
    MethodInfo toArrayMethod = typeof(Enumerable).GetMethod("ToArray")
        .MakeGenericMethod( new System.Type[]{ elementType } );

    var castedObjectEnum = castMethod.Invoke(null, new object[] { valueObj });
    var castedObject = toArrayMethod.Invoke(null, new object[] { castedObjectEnum });
    castedObject.Dump();
}

我确实得到了与 int 数组相对应的输出。按照发布的代码似乎是完全正常的。你的问题必须在别处。难道你实际上没有发送一个属性 List<object>,或者列表中包含了不是 int 的其他内容吗?
只需更改此行:
object valueObj = new List<object> { 1, 2, 3 };

转换为:

object valueObj = new List<object> { 1, 2, 3, "Test" };

给我抛出了异常。
也许你想使用OfType而不是Cast
如果你替换castMethod检索中的字符串,它又“能工作”,但当然它会过滤掉那个字符串。
这里需要更多的信息。

你说得对,我的valueObj有问题。它的类型是System.Collections.Generic.List`1[System.Object],我正在循环所有对象并使用Convert.ToInt32进行转换(只有三个0)。但是谢谢,我现在会朝这个方向进行调查,看看出了什么问题。 - Ultrakorne
在这种情况下,我使用了List<System.Int64>,所以它无法正常工作。我会看看需要做出哪些调整来解决这个问题。 - Ultrakorne

1

嗯,你有源代码 List<object> 并且可以获取其长度。

你可以使用 Array.CreateInstance 函数,并传入你的类型和长度。然后,你只需要一个一个地将项目移动过去即可。

为什么要使用linq呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接