带有数组参数和任意元素类型的C#FieldInfo.SetValue
我尝试使用反射设置数组字段,如下所示:带有数组参数和任意元素类型的C#FieldInfo.SetValue,c#,arrays,reflection,system.type,fieldinfo,C#,Arrays,Reflection,System.type,Fieldinfo,我尝试使用反射设置数组字段,如下所示: FieldInfo field = ... A[] someArray = GetElementsInSomeWay(); field.SetValue(this, someArray); arr2[0] = new object(); 该字段的类型为B[]B继承自A,而B的确切类型在编译时未知。 GetElementsInSomeWay()返回A[],但其中真正的元素都是BGetElementsInSomeWay()是一个库方法,无法更改 我最多只能
FieldInfo field = ...
A[] someArray = GetElementsInSomeWay();
field.SetValue(this, someArray);
arr2[0] = new object();
该字段的类型为B[]
B
继承自A
,而B
的确切类型在编译时未知。
GetElementsInSomeWay()
返回A[]
,但其中真正的元素都是B
GetElementsInSomeWay()
是一个库方法,无法更改
我最多只能用System.Type=field.FieldType.GetElementType()
获取B
。
但是,我无法将数组强制转换为所需的类型,例如。
someArray作为类型[]
,因为[]
在声明数组类型之前需要一个确切的类型。还是我在这里遗漏了什么?如果在运行时使用System.type
变量知道某个类型的数组,我可以声明该类型的数组吗
直接执行此操作会产生以下错误(此处A
是UnityEngine.Component
和B
是AbilityResult
,也可以是几十个其他类中的一个,所有这些类都从UnityEngine.Component
继承(可能通过一个长继承链):
经过一番探索,我偶然发现了这个问题: 我的问题的一个可能解决方案是:
A[] someArray = GetElementsInSomeWay();
System.Type type = field.FieldType.GetElementType();
Array filledArray = Array.CreateInstance(type, someArray.Length);
Array.Copy(someArray, filledArray, someArray.Length);
field.SetValue(this, filledArray);
我刚测试过,它能用
但是,我仍然希望避免复制元素。在我的例子中,阵列非常小(最多3-5个元素),但是如果有一个更干净的解决方案,我会很高兴看到它。经过一些搜索,我偶然发现了这个问题: 我的问题的一个可能解决方案是:
A[] someArray = GetElementsInSomeWay();
System.Type type = field.FieldType.GetElementType();
Array filledArray = Array.CreateInstance(type, someArray.Length);
Array.Copy(someArray, filledArray, someArray.Length);
field.SetValue(this, filledArray);
我刚测试过,它能用
但是,我仍然希望避免复制元素。在我的例子中,数组非常小(最多3-5个元素),但是如果有一个更干净的解决方案的话,那就很好了。我认为您需要更好地理解数组的变化。像
object[]
和string[]
这样的数组已经出现在.NET 1中,比泛型(.NET 2)早了很长时间。否则,它们可能被称为Array
和Array
现在,我们都知道任何字符串
都是对象
。如果这一事实意味着,对于某些“构造”Xxx
,任何Xxx
都是Xxx
,那么我们称之为。自.NET 4以来,一些通用接口和通用委托类型可以是covarinat,并且在其定义中用out
关键字标记,如中所示
public interface IEnumerable<out T>
{
// ...
}
因此,T[]
在.NET中是协变的。但是我刚才不是说我可以写(比如in
而不是out
)到一个数组吗?那么,如果我继续这样做会怎么样:
FieldInfo field = ...
A[] someArray = GetElementsInSomeWay();
field.SetValue(this, someArray);
arr2[0] = new object();
我正在尝试将一个不是字符串的对象
放入第0个插槽。上面的行必须编译(编译时类型的arr2
是object[]
)。但它也必须提出一个例外运行时间。这就是数组和协方差的问题
那么,逆变呢?试试这个:
object[] arrA = { new object(), DateTime.Now, "hello", };
string[] arrB = arrA; // won't compile, no cotravariance
从object[]
到string[]
进行显式转换仍然无法在运行时工作
现在,您的问题的答案是:您正在尝试对数组应用逆变换AbilityResult
是Component
,但这并不意味着Component[]
是AbilityResult[]
。编写GetElementsInSomeWay()
方法的人选择创建新组件[]
。即使他输入的所有组件都是AbilityResult
,仍然没有相反的结果。GetElementsInSomeWay()
的作者可以选择创建一个新功能result[]
。由于.NET数组的协方差,他仍然可以使用返回类型组件[]
要学习的课程:数组的实际类型(运行时类型,如.GetType()
所示)不会因为您强制转换而改变。NET允许协方差(类型为Component[]
的变量可能包含实际类型为AbilityResult[]
的对象)。最后,.NET不允许逆变(类型为AbilityResult[]
的变量从不包含对实际类型为Component[]
的对象的引用)
希望这有帮助。否则,我的答案应该会给你一些术语,你可以在谷歌上找到比我更好的解释。我认为你需要更好地理解数组的变化。像object[]
和string[]
这样的数组已经出现在.NET 1中,比泛型(.NET 2)早了很长时间。否则,它们可能被称为Array
和Array
现在,我们都知道任何字符串
都是对象
。如果这一事实意味着,对于某些“构造”Xxx
,任何Xxx
都是Xxx
,那么我们称之为。自.NET 4以来,一些通用接口和通用委托类型可以是covarinat,并且在其定义中用out
关键字标记,如中所示
public interface IEnumerable<out T>
{
// ...
}
因此,T[]
在.NET中是协变的。但是我刚才不是说我可以写(比如in
而不是out
)到一个数组吗?那么,如果我继续这样做会怎么样:
FieldInfo field = ...
A[] someArray = GetElementsInSomeWay();
field.SetValue(this, someArray);
arr2[0] = new object();
我正在尝试将一个不是字符串的对象
放入第0个插槽。上面的行必须编译(编译时类型的arr2
是object[]
)。但它也必须提出一个例外运行时间。这就是数组和协方差的问题
那么,逆变呢?试试这个:
object[] arrA = { new object(), DateTime.Now, "hello", };
string[] arrB = arrA; // won't compile, no cotravariance
从object[]
到string[]
进行显式转换仍然无法在运行时工作
现在,您的问题的答案是:您正在尝试对数组应用逆变换<代码>能力结果
是组件
,但这并不意味着组件[]
是能力