使用反射用基类数组填充派生类数组
Posted
技术标签:
【中文标题】使用反射用基类数组填充派生类数组【英文标题】:Use reflection to fill array of derived class with array of base class 【发布时间】:2017-11-07 01:48:24 【问题描述】:考虑以下问题: 我想在运行时用值填充 T 类型的数组。我能够获得所有持有这些实例之一的游戏对象(这里谈论 Unity3D)。这些游戏对象位于 results 数组中。 GetComponent 方法允许从游戏对象中提取 T 的实例,但会自动将其转换为 Ts 基类Component。 blueprint 包含有关绑定目标的信息,例如数组的 FieldInfo。
当前代码如下所示:
var arrayOfBaseClass =
(
from instance
in results
select instance.GetComponent(blueprint.Field.FieldType.GetElementType()))
.ToArray();
// Missing Step here
blueprint.Field.SetValue(o, arrayOfBaseClass);
SetValue 现在抛出 ArgumentException:对象类型 UnityEngine.Component[] 无法转换为目标类型:VEL.Input.ActionSignalReceiver[]
附加信息 arrayOfBaseClass 实际上是 T 的实例数组,只是通过 GetComponent 转换为基类型。如果我事先知道 T 手动转换为 T 将起作用并解决此问题。遗憾的是 T 事先不知道,并且可能在不同类型之间有所不同(但都派生自 Component)
现在的问题是,是否有办法使用 FieldInfo 的信息将数组转换回其最派生的类型。
【问题讨论】:
对阵列中的每个实例执行副本中提到的操作,然后就完成了。 我不认为这是链接问题的重复。首先,这不是将任意类转换为基类,其次,这个问题专门询问反射“SetValue”。我使用的类是派生类的实例,我只需要通过数组通过 SetValue 绑定它们。 从您的代码中很难看出results
、arrayOfDerivedClass
以及arrayOfBaseClass
实际上是什么。数组没有Field
-property。
我重写并试图澄清要点。感谢您的意见!
【参考方案1】:
通过一些试验和错误想通了,将在解释下方发布相关代码。 当我们在反射中工作时,我们需要一种方法来传递我们想要使用的目标类型。在这种情况下,我们可以通过在运行时构造一个泛型方法来做到这一点。
所以首先我们声明一个泛型函数,它接受一个目标对象、一个 fieldInfo(事先检查这是一个数组字段)和一个对象数组。这些对象被强制转换为目标类型 T,然后分配给字段:
public void BindToTypedArray<T> (object bindingTarget, FieldInfo field, object[] values)
var typedArray = from v in values select (T)v;
field.SetValue(bindingTarget, typedArray.ToArray());
要调用这个函数,我们需要知道类型 T,但是反射提供了一种在运行时通过 MakeGenericMethod 创建类型化泛型方法的方法。所以我们在上面的例子中所做的是,我们为上面的函数创建一个自定义类型的实例,并输入我们生成的对象数组:
var arrayOfBaseClass =
(
from instance
in results
select instance.GetComponent(blueprint.Field.FieldType.GetElementType()))
.ToArray();
// NEWCODE --------------------------------------------------------
MethodInfo bindArray= typeof(DataGlueController).GetMethod("BindToTypedArray");
MethodInfo bindArrayTyped=bindArray.MakeGenericMethod(blueprint.Field.FieldType.GetElementType());
bindArrayTyped.Invoke(this, new object[] o, blueprint.Field, arrayOfBaseClass );
// END NEWCODE ----------------------------------------------------
// blueprint.Field.SetValue(o, arrayOfBaseClass); <- this is done in the BindToTypedArray function
【讨论】:
以上是关于使用反射用基类数组填充派生类数组的主要内容,如果未能解决你的问题,请参考以下文章