将其类型谓词请阅读整个问题。我有一个独特的情况,有几个我想解决的限制。加载一个组件,而在另一个应用程序域
在我的代码有被编译成Predicate<System.Type>
表达式树。我的目标是加载程序集没有锁定它(这是该项目的输出组件,被不断地重修),适用其类型的列表在这个谓语并获得结果类型的回列表名:
// this is what I need:
return assembly.GetTypes().Where(t => predicate(t)).Select(t => t.FullName);
该程序集应该加载到另一个应用程序域中,因为我希望一收到我需要的信息就立即卸载它。
这是它得到棘手。有几个我正面临的问题:
如果我在另一个appdomain中加载程序集并简单地返回它的所有类型的数组,以便我可以将谓词应用回到我的主appdomain中,只要类型被编组回到我的主要应用程序域我得到一个FileNotFoundException
,指出该组件是找不到的。这使得sence,因为程序集只被加载到我创建的另一个appdomain中。在主应用程序域中加载它也会失败。
如果或者我尝试将谓词传递给另一个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容器注册的类型的使用情况(您可以观看它的工作原理的简短视频here)。
大多数情况下,分析容器注册非常简单 - 我只需检测足够的信息即可知道哪些具体类型受到影响。在Castle Windsor的这个例子中:Component.For<IFoo>().ImplementedBy<Foo>()
由此产生的类型是显而易见的,AllTypes.FromThisAssembly().BasedOn<IFoo>()
也是如此 - 给我提供足够的信息来对这条线会影响到的具体类型提供猜测。然而,考虑这个注册在温莎城堡:
container.Register(Classes
.FromAssemblyInDirectory(new AssemblyFilter(".").FilterByName(an => an.Name.StartsWith("Ploeh.Samples.Booking")))
.Where(t => !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dispatcher<>)))
.WithServiceAllInterfaces());
(source)
这里的信息取决于只会在运行时进行评估的谓词。
因为我所能做的就是静态分析这一点,所以我手里拿着来自Where
子句的lambda表达式的ReSharper AST(在ReSharper中称为PSI)表示。我可以将这个AST转换成一个LINQ表达式树,然后将它编译成一个委托。
我的想法是是加载通过反射输出组件(由FromAssembly*
描述符确定),并且为了获得类型名(我只需要姓名)在组装的类型应用此委托。每次装配改变时都必须重新评估(我不关心性能的这一点)。总之,除非有人能够推荐一种更好的方式来确定受谓词影响的类型,我想知道如何用反射来做到这一点(不幸的是我没有考虑过其他元数据读者,因为我会必须以某种方式将lambda表达式AST转换为不同数据类型的谓词,并且我不知道是否存在1对1转换)。
谢谢您的阅读。这个问题在可用时将有500点奖励。
如果'Expression'是序列化,你可以创建'Predicate'委托作为一个'Expression',并将其传递给appdomain边界,然后在'remote'appdomain中进行编译。但可悲的是,那不是那种情况:( – leppie
@leppie是的,我想过序列化表达式并传递它,你是对的,它并不像听起来那么简单... –