Iga*_*nik 8 .net reflection resharper delegates appdomain
请阅读整个问题.我有一个独特的情况,有几个限制,我想解决.
在我的代码中,我有一个表达式树,编译成一个Predicate<System.Type>.我的目标是加载程序集而不锁定它(它是项目的输出程序集,不断重建),将此谓词应用于其类型列表并返回结果类型名称列表:
// this is what I need:
return assembly.GetTypes().Where(t => predicate(t)).Select(t => t.FullName);
Run Code Online (Sandbox Code Playgroud)
这个程序集应该加载到另一个appdomain中,因为我想在得到我需要的信息后立即卸载它.
这是它变得棘手的地方.我面临几个问题:
如果我在另一个appdomain中加载程序集并简单地返回所有类型的数组,那么我可以将谓词应用到我的主appdomain中,只要将类型编组回我的主应用程序域,我就会得到一个FileNotFoundException,说明找不到这个组件.这样就可以了,因为程序集只是在我创建的另一个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 Container注册,并帮助ReSharper找出通过DI Container注册的类型的使用情况(您可以在这里观看有关其工作原理的简短视频).
在大多数情况下,分析容器注册很简单 - 我只需要检测足够的信息以了解哪些具体类型受到影响.在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());
Run Code Online (Sandbox Code Playgroud)
(来源)
这里的信息取决于只在运行时进行评估的谓词.
由于我所能做的就是对此进行静态分析,因此我手中有ReSharper的AST(在ReSharper中称为PSI)表示该Where子句中的lambda表达式.我可以将此AST转换为LINQ表达式树,然后将其编译为委托.
我的想法是FromAssembly*通过反射加载输出程序集(由描述符确定),并在程序集的类型上应用此委托以获取类型名称(我只需要名称).每次组件更改时都必须重新评估(我不关心这一点的性能).
总之,除非有人可以推荐一种更好的方法来确定受谓词影响的类型,我想知道如何用反射来做到这一点(遗憾的是我没有考虑其他元数据读者,因为我必须以某种方式转换lambda表达式AST为不同数据类型的谓词,我不知道是否存在1对1转换).
谢谢你的阅读.当这个问题变得可用时,它将获得500点奖励.
您需要加载程序集才能获取Type实例,因此单独的解决方案AppDomain似乎是正确的解决方案。
因此,您需要将谓词Expression放入 that 中AppDomain,这意味着您必须对其进行序列化/反序列化。
由于各种原因,这种要求变得越来越频繁。我之所以关注这个,是因为我想在 WCF 服务中注入 Linq to Entities 表达式。
幸运的是,有一些现有的实现。
我找到了这个:CodePlex - Expression Tree Serializer
我刚刚用 测试过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
Run Code Online (Sandbox Code Playgroud)