簡體   English   中英

C#FieldInfo.SetValue,帶有數組參數和任意元素類型

[英]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變量在運行時知道類型,我可以聲明某種類型的數組嗎?

以直接方式執行此操作會產生以下錯誤(此處AUnityEngine.ComponentBAbilityResult ,它也可以是幾十個其他類之一,都可以從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<>反轉關系,則稱為逆變。 所以“ stringobject ”,逆變成“ Xxx<object>Xxx<string> ”。

現在,回到陣列。 這里的一個自然問題是:數組是協變的還是逆變的,或者兩者都不是(“不變”)? 既然你可以讀取和寫入數組中的每個“單元格”,它們就不能完全協變或逆變。 但試試這段代碼:

string[] arr1 = { "these", "are", "strings", };
object[] arr2 = arr1;                           // works! covariance!
var runtimeType = arr2.GetType();               // System.String[]

所以T[]在.NET中是協變的。 但沒我只想說,我可以寫(如inout )到數組? 那么如果我繼續這樣做怎么辦:

arr2[0] = new object();

我正在嘗試將一個不是 stringobject放入第零個插槽中。 上面的行必須編譯(編譯時類型的arr2object[] )。 但它也必須提高運行時間。 這就是數組和協方差的問題。

那么逆轉呢? 嘗試這個:

object[] arrA = { new object(), DateTime.Now, "hello", };
string[] arrB = arrA;  // won't compile, no cotravariance

object[]string[]進行顯式轉換仍然無法運行。

現在,您的問題的答案:您正試圖將逆變應用於數組。 AbilityResultComponent ,但這並不意味着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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM