通过反射获取含私有Setter的类属性遇到的异常问题
反射获取带私有Setter属性时的继承类问题
我尝试通过反射获取类中所有带有私有Setter的属性,过程看似简单却遇到了一个异常但符合CLR行为逻辑的问题。
我的初始实现
我写了这样一个Type扩展方法:
public static IEnumerable<PropertyInfo> InstanceProperties(this Type type) { List<PropertyInfo> results = new(); var allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in allProperties) { var setMethod = property.GetSetMethod(true); if (setMethod != null && setMethod.IsPrivate) { results.Add(property); } } return results; }
测试用类与测试代码
为了验证逻辑,我创建了简单的继承类:
public class BaseClass { public string Name { get; private set; } public BaseClass(string name) { Name = name; } } public class DerivedClass : BaseClass { public string Description { get; private set; } public DerivedClass(string name, string description) : base(name) { Description = description; } }
对应的测试代码:
[Fact] public void InstanceProperties_WithBaseType_ReturnsAllProperties() { // Arrange Type baseEntityType = typeof(BaseClass); // Act var result = baseEntityType.InstanceProperties(); // Assert result.Should().NotBeNullOrEmpty(); result.Count().Should().Be(1); } [Fact] public void InstanceProperties_WithDerivedType_ReturnsAllProperties() { // Arrange Type baseEntityType = typeof(DerivedClass); // Act var result = baseEntityType.InstanceProperties(); // Assert result.Should().NotBeNullOrEmpty(); result.Count().Should().Be(2); }
问题现象
第一个测试(针对BaseClass)正常通过,但第二个测试(针对DerivedClass)失败了。具体表现为:type.GetProperties(BindingFlags.Public | BindingFlags.Instance)确实返回了两个属性(Name和Description),但基类的Name属性调用GetSetMethod(true)却返回null——这和直接针对BaseClass获取时能找到私有Setter的情况完全相反。
请问该如何解释这一行为,以及如何解决?
补充说明
根据反馈,进一步明确我的最终需求:要构造的对象类型需满足:
- 可直接继承自知名基类(如
Entity),该基类有一个带私有Setter的Guid类型唯一实例属性 - 可继承自抽象基类,而该抽象基类又继承自
Entity - 所有实例属性均带有私有Setter
- 所有类都有一个名为
Create的公共静态工厂方法,不同类的方法参数不同
另外我还想了解,Entity Framework是如何处理这种构造方式的,因为它会使用私有无参构造函数创建对象实例。
最终解决方案
我最终编写了一个解决方案,和Jamiec、Gert Arnold提出的方案非常相似,分享出来供大家参考!感谢各位的帮助!
public static IEnumerable<PropertyInfo> InstanceProperties(this Type type) { List<PropertyInfo> results = new(); Type? leafType = type; while (leafType != null) { var allProperties = leafType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var property in allProperties) { var accessors = property .GetAccessors(true) .Where(a => a.ReturnType == typeof(void) && a.IsPrivate) .ToArray(); foreach (var accessor in accessors) { results.Add(property); } } leafType = leafType.BaseType; } return results; }
内容的提问来源于stack exchange,提问作者Mammt
相关产品推荐
相关产品推荐

