使用反射调用SubjectAlternativeNameBuilder的AddGeneralName方法时遭遇空引用异常,如何正确实现?
使用反射调用SubjectAlternativeNameBuilder的AddGeneralName方法时遭遇空引用异常,如何正确实现?
嘿,我来帮你捋捋问题出在哪,以及怎么搞定这个反射调用的问题。
首先,你遇到的NullReferenceException根源很明确:你调用typeof(SubjectAlternativeNameBuilder).GetMethod("AddGeneralName")的时候,没有指定绑定标志来获取非公开方法。AddGeneralName是SubjectAlternativeNameBuilder的内部非公开方法,默认的GetMethod只会查找公开方法,所以你拿到的methodInfo其实是null,最后调用Invoke的时候自然就空引用了。
另外,还有个隐藏的坑:你只给GeneralNameAsn设置了RegisteredId字段,但这个ASN.1类型是带类型标记的——它需要明确指定当前是哪种类型的通用名称(比如这里的RegisteredId),否则内部处理的时候也会出问题。
接下来给你修正后的完整代码,每一步我都标清楚为什么这么改:
var assembly = typeof(SubjectAlternativeNameBuilder).Assembly; // 获取GeneralNameAsn类型 var generalNameAsnType = assembly.GetType("System.Security.Cryptography.Asn1.GeneralNameAsn"); // 获取对应的类型枚举(用来标记当前是RegisteredId类型) var generalNameTypeEnum = assembly.GetType("System.Security.Cryptography.Asn1.GeneralNameType"); // 创建GeneralNameAsn实例 var generalNameAsn = Activator.CreateInstance(generalNameAsnType); // 1. 先设置类型标记:必须指定这是RegisteredId类型 var typeField = generalNameAsnType.GetField("_type", BindingFlags.Instance | BindingFlags.NonPublic); typeField.SetValue(generalNameAsn, Enum.Parse(generalNameTypeEnum, "RegisteredId")); // 2. 设置RegisteredId的值(注意字段名是带下划线的内部字段,不是你原来写的RegisteredId) var registeredIdField = generalNameAsnType.GetField("_registeredId", BindingFlags.Instance | BindingFlags.NonPublic); registeredIdField.SetValue(generalNameAsn, "1.3.6.1.4.1.311.20.2.3"); // 3. 正确获取非公开的AddGeneralName方法:必须指定BindingFlags,同时明确参数类型 var addGeneralNameMethod = typeof(SubjectAlternativeNameBuilder) .GetMethod("AddGeneralName", BindingFlags.Instance | BindingFlags.NonPublic, new[] { generalNameAsnType }); // 4. 调用方法 var sanBuilder = new SubjectAlternativeNameBuilder(); addGeneralNameMethod.Invoke(sanBuilder, new[] { generalNameAsn }); // 之后就可以正常使用sanBuilder生成SAN了 var san = sanBuilder.Build();
我再给你划几个关键的注意点:
- 调用
GetMethod时一定要加BindingFlags.Instance | BindingFlags.NonPublic,否则拿不到内部方法;同时指定参数类型可以避免重载导致的匹配问题。 - .NET的内部类型字段通常会用下划线开头(比如
_type、_registeredId),不要直接用公开属性的名称去反射字段。如果不确定字段名,可以用generalNameAsnType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)打印所有字段来确认。 - 必须给
GeneralNameAsn设置类型标记,这个是ASN.1结构的要求,不设置的话即使调用成功,后续生成SAN也会失败。
如果之后还是遇到问题,可以先检查这几点:字段名是否匹配、绑定标志是否正确、类型标记有没有设置到位。
备注:内容来源于stack exchange,提问作者Yola
相关产品推荐
相关产品推荐

