.NET5环境下运行时GetCustomAttribute返回null问题求解
我有一段加载程序集并通过属性对数据进行分类的代码。
我尝试获取实际的CustomAttribute对象,在.NET Framework下调试时代码可正常返回对应值,在.NET5环境下运行时该方法返回null。
补充说明1
查阅官方文档后发现:
.NET Framework version 2.0 provides a new load context, the reflection-only context, which can be used to examine code that cannot be loaded for execution.
补充说明2
经排查问题原因为:我尝试在运行时获取属性对象,属性以及其他仅反射上下文中的运行时内容无法被加载,因此方法返回null。
核心疑问
请问除了使用System.Reflection外,还有什么其他方案可以在运行时获取到实际的属性对象?
字典初始化代码
var ass = Assembly.LoadFile(Path.GetFullPath("MyInterface.dll")); var asss = Assembly.GetExecutingAssembly(); var apiInterfaces = ass.DefinedTypes.Where(x => x.IsInterface && x.CustomAttributes != null && x.CustomAttributes.Any(z => z.AttributeType.FullName != null && z.AttributeType.FullName.Equals(typeof(ApiInterfaceDescriptorAttribute).FullName)));
自定义属性定义
[AttributeUsage(AttributeTargets.Interface)] public class ApiInterfaceDescriptorAttribute : Attribute { public string ApiUsageName { get; } public ApiInterfaceDescriptorAttribute(string apiUsageName) { ApiUsageName = apiUsageName; } }
示例接口代码
[ApiInterfaceDescriptor("powercontrol")] public interface IMyInterface { [ApiMethodDescriptor(ApiExposureLevel.Basic, "a-method...")] void SomeMethod(); }
获取属性的代码片段
public class ApiDetector { private Dictionary<Type, List<MethodInfo>> _apiDictionary = new Dictionary<Type, List<MethodInfo>>(); public void LoadApiElements() { var apiKeyDesriptor = key.GetCustomAttribute(typeof(ApiInterfaceDescriptorAttribute)) as ApiInterfaceDescriptorAttribute; _apiDetector.Add(new ApiDataObjectDescriptor { Name = key.Name, ApiUsageName = apiKeyDesriptor?.ApiUsageName, Type = key }); } }
- 本地运行可正常获取属性实例:

- .NET5远程机器运行返回null:

修正程序集加载逻辑
该问题本质是.NET5+与.NET Framework的程序集加载上下文差异导致的,Assembly.LoadFile会将程序集加载到独立上下文,和当前执行域的Attribute类型不匹配,才会返回null。直接改用Assembly.LoadFrom替代LoadFile,程序集将加载到当前上下文,属性类型匹配后即可正常获取实例。仅反射上下文兼容方案
如果必须使用仅反射上下文加载程序集,可以直接读取CustomAttributeData的构造参数,手动构造Attribute实例,不需要依赖类型匹配即可拿到属性值,示例代码如下:
var attrData = x.CustomAttributes.First(z => z.AttributeType.FullName == typeof(ApiInterfaceDescriptorAttribute).FullName); var descriptor = new ApiInterfaceDescriptorAttribute(attrData.ConstructorArguments[0].Value.ToString());
该方案不需要调整现有反射逻辑框架,即可拿到期望的属性值。
- 编译期预生成映射方案
如果要完全规避运行时反射的上下文问题,可以使用Source Generator在编译期扫描所有标记了目标属性的接口,生成静态的属性映射字典,运行时直接读取字典即可,性能也优于运行时反射,适合对启动速度有要求的场景。
内容的提问来源于stack exchange,提问作者Michael Gabbay

