簡體   English   中英

通過反射從其字符串創建任何類型實例

[英]Create any type instance from its string via reflection

想象以下情況:

用戶將代表.NET類型的字符串傳遞給應用程序,例如stringSystem.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);

obj1string一個實例,但是obj2將失敗,因為變量t2null (意味着,給定代碼中的第二行無法找到“復雜”類型)。


編輯№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創建通用類型的實例並將其強制轉換回該類型?

我(暫時)解決了以下問題:

  1. 檢查給定的字符串是否包含<>
  2. 如果是這樣,請根據下面提供的函數( ParseGeneric )解析字符串,然后繼續使用解析的標記遞歸
  3. 如果不是,請檢查是否出現了數組括號( [][][][,]等)
  4. 使用遞歸Array::CreateInstance(Type,int[])相應地解析類型
  5. 檢查是否存在任何指針'stars'( * ),並使用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.

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