如何通过编程方式查找并追踪.NET中标记为转发的类型
类型转发查询失败原因
你调用GetForwardedTypes()和查找TypeForwardedToAttribute没有返回File类型相关信息,核心原因是运行时加载的System.IO程序集和编译期引用的System.IO程序集不是同一个:
- 你通过
Assembly.Load("System.IO")加载的是运行时实现程序集,本身已经不包含转发特性,转发标记只存在于面向编译场景的引用程序集(Reference Assembly)中 - .NET 5+的共享框架中,大量基础类型的转发逻辑只在引用程序集里保留,运行时程序集仅保留实际实现的类型,自然查不到相关标记
编程获取类型转发信息的方案
方案1:使用System.Reflection.Metadata直接读取引用程序集元数据
这是最稳定的方案,避开运行时加载的限制:
using System.Reflection.Metadata; using System.Reflection.PortableExecutable; // 先定位到对应版本的System.IO引用程序集路径,.NET引用程序集一般在 C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\ 对应版本目录下 string refAssemblyPath = @"path\to\System.IO.dll"; using var fs = File.OpenRead(refAssemblyPath); using var peReader = new PEReader(fs); MetadataReader mdReader = peReader.GetMetadataReader(); foreach (var attrHandle in mdReader.CustomAttributes) { CustomAttribute attr = mdReader.GetCustomAttribute(attrHandle); StringHandle attrTypeName = mdReader.GetTypeReference((TypeReferenceHandle)attr.Constructor.Kind).Name; if (mdReader.GetString(attrTypeName) != "TypeForwardedToAttribute") continue; CustomAttributeValue<Type> attrValue = attr.DecodeValue(new DummyAttributeTypeProvider()); Type forwardedType = (Type)attrValue.FixedArguments[0].Value; if (forwardedType.FullName == "System.IO.File") { Console.WriteLine($"转发目标程序集:{forwardedType.Assembly.FullName}"); break; } } // 简易的Attribute类型提供器实现,只需要处理TypeForwardedToAttribute的参数解析 class DummyAttributeTypeProvider : ICustomAttributeTypeProvider<Type> { public Type GetTypeFromSerializedName(string name) => Type.GetType(name); public PrimitiveTypeCode GetPrimitiveTypeCode(Type type) => PrimitiveTypeCode.Type; // 其他接口方法直接抛NotImplementedException即可,不需要完整实现 }
方案2:利用编译错误信息提取(适配Razor场景)
如果你的场景就是Razor编译,可以直接捕获CS1069错误,从错误文本里直接解析出缺失的程序集名称,动态添加引用即可,不需要提前查询所有转发类型:
- 错误文本里固定会给出转发目标程序集的完整名称,直接正则提取
Consider adding a reference to that assembly前面的程序集名称即可
Razor编译场景的处理方案
你可以按以下步骤解决依赖注入问题:
- 优先引用
Microsoft.AspNetCore.App共享框架的所有程序集,而不是手动逐个添加基础库引用,Razor编译默认依赖这个共享框架的所有基础类型 - 如果必须手动控制引用列表,提前收集所有.NET基础库的转发对应关系,或者在编译报错后动态提取缺失的程序集、添加引用后重试编译即可
内容的提问来源于stack exchange,提问作者BJury
相关产品推荐
相关产品推荐

