![](/img/trans.png)
[英]C# How to call FieldInfo.SetValue function without manual type conversion
[英]C# FieldInfo.SetValue with an array parameter and arbitrary element type
我試圖使用這樣的反射設置一個數組字段:
FieldInfo field = ...
A[] someArray = GetElementsInSomeWay();
field.SetValue(this, someArray);
該字段具有類型B[]
。 B
繼承自A
並且在編譯時不知道B
的確切類型。 GetElementsInSomeWay()
返回A[]
但里面的真實元素都是B
的。 GetElementsInSomeWay()
是一個庫方法,無法更改。
我最多可以做的是使用System.Type type = field.FieldType.GetElementType()
獲取B
但是我無法將數組轉換為所需的類型,例如someArray as type[]
因為[]
在聲明數組類型之前需要一個確切的類型。 或者我在這里遺漏了什么? 如果使用System.Type
變量在運行時知道類型,我可以聲明某種類型的數組嗎?
以直接方式執行此操作會產生以下錯誤(此處A
是UnityEngine.Component
, B
是AbilityResult
,它也可以是幾十個其他類之一,都可以從UnityEngine.Component
繼承(可能通過長繼承鏈):
ArgumentException: Object type UnityEngine.Component[] cannot be converted to target type: AbilityResult[]
Parameter name: val
System.Reflection.MonoField.SetValue (System.Object obj, System.Object val, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) (at /Applications/buildAgent/work/3df08680c6f85295/mcs/class/corlib/System.Reflection/MonoField.cs:133)
System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) (at /Applications/buildAgent/work/3df08680c6f85295/mcs/class/corlib/System.Reflection/FieldInfo.cs:150)
我認為你需要更好地理解數組的方差 。 像object[]
和string[]
這樣的數組已經出現在.NET 1中,比仿制葯(.NET 2)早了很久。 否則,它們可能被稱為Array<object>
和Array<string>
。
現在,我們都知道任何string
都是一個object
。 如果這個事實暗示,對於某些“構造” Xxx
,任何Xxx<string>
都是Xxx<object>
,那么我們稱之為covaraince 。 從.NET 4開始,一些通用接口和通用委托類型可以是covarinat,並且在其定義中標記為out
關鍵字,如
public interface IEnumerable<out T>
{
// ...
}
如果在“應用” Xxx<>
反轉關系,則稱為逆變。 所以“ string
是object
”,逆變成“ Xxx<object>
是Xxx<string>
”。
現在,回到陣列。 這里的一個自然問題是:數組是協變的還是逆變的,或者兩者都不是(“不變”)? 既然你可以讀取和寫入數組中的每個“單元格”,它們就不能完全協變或逆變。 但試試這段代碼:
string[] arr1 = { "these", "are", "strings", };
object[] arr2 = arr1; // works! covariance!
var runtimeType = arr2.GetType(); // System.String[]
所以T[]
在.NET中是協變的。 但沒我只想說,我可以寫(如in
未out
)到數組? 那么如果我繼續這樣做怎么辦:
arr2[0] = new object();
我正在嘗試將一個不是 string
的object
放入第零個插槽中。 上面的行必須編譯(編譯時類型的arr2
是object[]
)。 但它也必須提高運行時間。 這就是數組和協方差的問題。
那么逆轉呢? 嘗試這個:
object[] arrA = { new object(), DateTime.Now, "hello", };
string[] arrB = arrA; // won't compile, no cotravariance
從object[]
到string[]
進行顯式轉換仍然無法運行。
現在,您的問題的答案:您正試圖將逆變應用於數組。 AbilityResult
是Component
,但這並不意味着Component[]
是AbilityResult[]
無論誰編寫了GetElementsInSomeWay()
方法,都選擇創建一個new Component[]
。 即使他投入的所有組件都是AbilityResult
,仍然沒有逆轉。 GetElementsInSomeWay()
的作者本可以選擇創建一個new AbilityResult[]
。 他仍然可以返回類型Component[]
,以獲取.NET數組的協方差。
要學習的課程:數組的實際類型(由.GetType()
顯示的運行時類型)不會因為你的演員而改變。 .NET確實允許協方差( Component[]
類型的變量可能包含一個實際類型為AbilityResult[]
的對象)。 最后,.NET 不允許逆變(類型的變量AbilityResult[]
從不保存到真實類型的對象的引用Component[]
希望這可以幫助。 否則,我的答案應該給你一些條款,你可以谷歌找到優於我的解釋。
經過一番搜索,我偶然發現了這個問題: 如何使用Reflection創建一個C#數組,只輸入信息?
我的問題的一個可能的解決方案是:
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個元素),但是如果有一個更清晰的解決方案,那將是很好的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.