載入程序集並在另一個應用程序域中對其類型應用謂詞
請閱讀整個問題。我有一個獨特的情況,有幾個我想解決的限制。
在我的程式碼中,我有一個表達式樹,它被編譯為
Predicate<System.Type>. 我的目標是載入一個程序集而不鎖定它(它是項目的輸出程序集,不斷重建),將此謂詞應用於其類型列表並返回結果類型名稱的列表:// this is what I need: return assembly.GetTypes().Where(t => predicate(t)).Select(t => t.FullName);這個程序集應該載入到另一個 appdomain 中,因為我想在獲得所需資訊後立即解除安裝它。
這就是棘手的地方。我面臨幾個問題:
如果我在另一個 appdomain 中載入程序集並簡單地返回其所有類型的數組,以便我可以將謂詞應用回我的主 appdomain 中,只要將類型編組回我的主 appdomain,我就會得到一個
FileNotFoundException,說明未找到此程序集。這是有道理的,因為程序集只被載入到我創建的另一個 appdomain 中。將它也載入到主應用程序域中會破壞目的。或者,如果我嘗試將謂詞傳遞到另一個應用程序域,將其應用到那裡並取回一個字元串數組(完整類型名稱),我會得到一個
SerializationException: "Cannot serialize delegates over unmanaged function pointers, dynamic methods or methods outside the delegate creator's assembly.",因為謂詞是一個動態方法(從表達式樹編譯) .將它載入到主應用程序域中不會有任何這些問題,但是由於在不解除安裝整個應用程序域的情況下無法解除安裝已載入的程序集,因此一旦程序集發生更改(重建後),任何嘗試載入具有相同名稱的程序集會導致異常。
上下文:
我正在為 ReSharper 建構一個名為Agent Mulder的外掛。該外掛背後的想法是分析解決方案中的 DI/IoC 容器註冊,並幫助 ReSharper 找出通過 DI 容器註冊的類型的使用情況(您可以在此處觀看有關其工作原理的簡短影片)。
在大多數情況下,分析容器註冊很簡單——我只需要檢測足夠的資訊就可以知道哪些具體類型受到影響。在這個溫莎城堡
Component.For<IFoo>().ImplementedBy<Foo>()的例子中:結果類型是顯而易見的,所以是AllTypes.FromThisAssembly().BasedOn<IFoo>()- 給我足夠的資訊來猜測將受這條線影響的具體類型。但是,請考慮在 Castle Windsor 中進行的此註冊:container.Register(Classes .FromAssemblyInDirectory(new AssemblyFilter(".").FilterByName(an => an.Name.StartsWith("Ploeh.Samples.Booking"))) .Where(t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dispatcher<>))) .WithServiceAllInterfaces());(來源)
此處的資訊取決於僅在執行時評估的謂詞。
由於我所能做的就是靜態分析這一點,因此我手上有 ReSharper 的 AST(在 ReSharper 中稱為 PSI)表示
Where子句中的 lambda 表達式。我可以將此 AST 轉換為 LINQ 表達式樹,然後將其編譯為委託。我的想法是通過反射載入輸出程序集(由
FromAssembly*描述符確定),並將此委託應用於程序集的類型以獲得類型名稱(我只需要名稱)。每次組件更改時都必須重新評估這一點(我現在不關心性能)。總之,除非有人可以推荐一種更好的方法來確定受謂詞影響的類型,否則我想知道如何通過反射來做到這一點(不幸的是我沒有考慮其他元數據閱讀器,因為我必須以某種方式轉換將 lambda 表達式 AST 轉換為不同數據類型的謂詞,我不知道是否存在 1 對 1 的轉換)。
感謝您的閱讀。此問題可用時將獲得 500 點獎勵。
您需要載入程序集以獲取
Type實例,因此單獨的AppDomain似乎是正確的解決方案。因此,您需要將謂詞
Expression放入 that 中AppDomain,這意味著您必須對其進行序列化/反序列化。由於各種原因,這種要求變得越來越頻繁。我在看這個是因為我想通過 WCF 服務將 Linq 噴射到實體表達式。
幸運的是,有一些現有的實現。
我找到了這個:CodePlex - 表達式樹序列化器
我剛剛用 測試了它
Types,這有效:Expression<Func<Type,bool>> predicate = t => ( !t.IsGenericType && t.Name == "Int32" ); var s = new ExpressionSerialization.ExpressionSerializer(); var xml = s.Serialize( predicate ); var p = s.Deserialize( xml ) as Expression<Func<Type, bool>>; var f = p.Compile(); Console.WriteLine( "Int32: " + f( typeof( int ) ) ); // true Console.WriteLine( "String: " + f( typeof( string ) ) ); // false