PostSharp自定义属性引发TypeLoadException问题及依赖疑问
问题解答
为什么单元测试项目必须直接依赖Lib?
这是C# CLR的元数据加载机制导致的:
- 自定义属性会作为元数据嵌入到被标注的方法/类型所在的程序集(也就是Service)里,但CLR加载这些元数据时,会尝试解析属性的原始类型定义。
- 当单元测试项目调用Service中的
method时,CLR需要加载method的元数据,其中包含对attribute类型的引用。如果单元测试项目的依赖链里没有Lib,CLR找不到这个类型的定义,就会抛出System.TypeLoadException。 - 这里依赖传递不生效的原因是:虽然Service依赖Lib,但.NET默认的依赖传递针对的是运行时需要直接调用的类型,而属性作为元数据依赖,CLR会直接尝试加载它的类型,不管有没有被显式调用。
PostSharp注解的场景
PostSharp的注解本质也是基于自定义属性实现的切面,所以遵循同样的CLR规则:
- 要是你在API门面层用PostSharp注解,API的消费者(比如调用API的客户端)如果需要加载门面层的类型元数据(比如反射场景、或者直接引用门面层程序集调用方法),就必须直接依赖包含PostSharp注解属性的程序集。
- 只有一种例外:如果PostSharp在编译时已经把切面逻辑完全织入目标程序集(比如把注解的逻辑直接编译成目标方法的一部分,不再保留对注解属性的元数据引用),这时消费者就不需要依赖注解所在的程序集了。但默认情况下PostSharp会保留元数据引用,除非你做了特殊配置。
怎么避免直接依赖?
要是不想让单元测试或消费者直接依赖Lib,可以试试这几种方法:
- 配置PostSharp的编译时织入,移除元数据引用:让PostSharp编译Service项目时,把属性的逻辑完全注入到
method里,同时删掉对attribute类型的元数据引用。 - 把属性定义移到一个所有消费者都会依赖的公共类库中,而不是单独的Lib。
- 避免在对外暴露的方法/类型上使用需要消费者依赖的自定义属性,把属性用在内部实现的类型上。
内容的提问来源于stack exchange,提问作者stan
相关产品推荐
相关产品推荐

