考虑以下问题: 我想在运行时用值填充T类型的数组。我能够获得所有GameObjects(在这里谈论Unity3D),其中包含其中一个实例。这些GameObject位于结果数组中。 GetComponent方法允许从gameObject中提取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的信息将数组强制转换回其派生类型。
答案 0 :(得分:0)
通过一些试验和错误计算出来,将在相关代码下面发布解释。 当我们在反射中工作时,我们需要一种方法来传递我们想要使用的目标类型。在这种情况下,我们可以通过在运行时构造泛型方法来实现。
首先,我们声明一个泛型函数,它接受一个目标对象,一个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