[英]Create any type instance from its string via reflection
想象以下情況:
用戶將代表.NET類型的字符串傳遞給應用程序,例如string
或System.IntPtr
。 假設所討論的應用程序可以訪問在其中定義了給定類型的程序集,則可以基於字符串創建給定類型的實例。
我已經設法創建了這樣的應用程序; 問題僅僅是,我還不能創建“復雜”或“嵌套”類型,例如:
System.Tuple<string, System.Action>
類的泛型 T
數組,例如int[]
, System.IntPtr[]
等。 T
指針,例如int*
, char**
, Namespace.MyStruct*
等。 我的問題是:僅給出類型的字符串表示形式(當然還有所有必需的程序集)時,如何創建此類嵌套類型實例?
.NET BCL是否包含某種string --> Type
-parser? 還是我必須使用某種形式的遞歸regex-parser和Activator.CreateInstance
?
編輯№1:
由於這個問題似乎太廣泛了,我將嘗試澄清一下自己:
我能夠為“簡單”類型創建類型實例-但是,我正在努力創建“復雜”類型的類型實例,例如:
Type t1 = typeof(string).Assembly.GetType("System.String");
Type t2 = typeof(string).Assembly.GetType("System.Tuple<System.String, System.Int32>");
object obj1 = Activator.CreateInstance(t1);
object obj2 = Activator.CreateInstance(t2);
obj1
是string
一個實例,但是obj2
將失敗,因為變量t2
為null
(意味着,給定代碼中的第二行無法找到“復雜”類型)。
編輯№2:
Type::MakeGenericType(Type[])
的使用顯然很有幫助,但是創建這種類型的實例的最簡單/最快(?)方式將是怎樣的:
IEnumerable<Tuple<int[,], char[][], Dictionary<string, Func<int, int*, byte>>>>
我將不得不編寫某種基於正則表達式的解析器,該解析器在給定字符串的不同部分上進行遞歸迭代。
編輯№3:
我發現了System::CodeDom::CodeTypeReference
並且我目前正在尋找一種基於給定CodeTypeReference
-instance(可以使用類型的字符串表示形式創建)來獲取類型的方法。
編輯№4:( 對不起所有編輯)
我想我在這篇SO帖子中找到了解決方案。
我可能會丟失一些東西,但是看起來您在尋找Reflection 。 具體來說,就是GetType
方法。 文檔指出有關此方法的以下內容:
獲取具有指定名稱的Type,執行區分大小寫的搜索。
然后,您將要查看Activator.CreateInstance
:
使用該類型的默認構造函數創建指定類型的實例
但是,在為泛型類型創建實例之前,您將需要查看`Type.MakeGenericType' :
將類型數組的元素替換為當前泛型類型定義的類型參數,並返回表示所得構造類型的Type對象。
您可能還會發現其他問題的答案也很有用: 如何使用Activator創建通用類型的實例並將其強制轉換回該類型?
我(暫時)解決了以下問題:
<
或>
ParseGeneric
)解析字符串,然后繼續使用解析的標記遞歸 []
, [][]
, [,]
等) Array::CreateInstance(Type,int[])
相應地解析類型 *
),並使用Marshal::StructureToPtr
相應地解析類型。 ParseGeneric
方法:
public static Type FetchGenericType(string typestring) { Match m; if ((m = Regex.Match(typestring, )).Success) { string cls = m.Groups["class"].ToString(); string par = m.Groups["params"].Success ? m.Groups["params"].ToString() : ""; List<string> paramtypes = new List<string>(); int s = 0, e = 0; for (int i = 0, c = 0, l = par.Length; i < l; i++) switch (par[i]) { case ',': if (c > 0) goto default; paramtypes.Add(par.Substring(s, e)); s = i + 1; e = 0; break; case '<': ++c; goto default; case '>': --c; goto default; default: ++e; break; } // I know, that this is bad as hell, but what should I do instead? paramtypes.Add(par.Substring(s, e)); IEnumerable<Type> @params = from type in paramtypes where !string.IsNullOrWhiteSpace(type) select FetchGenericType(type); string paramstring = string.Join(", ", from type in @params select "[" + type.FullName + ", " + type.Assembly.GetName().Name + "]"); string result = @params.Count() == 0 ? cls : string.Format("{0}`{1}[{2}]", cls, @paramsCount(), paramstr); // The string has now the format '...List`1[[System.String, mscorlib]]' // or: 'System.Tuple[[System.Int32, mscorlib], [System.Object, mscorlib]]' ... return FetchType(result); } else return FetchType(typestring); }
函數FetchType
執行一些基本的數組括號解析,然后通過查看給定的程序集,基於結果字符串獲取類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.