我正在尝试获取具有私有设置器的类的所有属性。这似乎很简单,但是我遇到了一种奇怪但可能正常的行为。
这是我已经实施的解决方案
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);
}
第一个测试成功,而第二个测试失败。更具体地说,在第二个测试中,代码 varallProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
返回两个属性,但基类的属性没有 setter 方法。这与第一个测试不一致,因为在第一个测试中,该属性确实有一个定义为私有的 set 方法。
关于这种行为有什么建议/解释吗?
编辑 根据评论的建议,我更好地解释问题的范围。最终目标是构造具有以下特征的某些类型的对象:
- 可以是直接从众所周知的基类继承的类(例如
Entity
),该基类具有一个带有私有设置器的 Guid 类型的唯一实例属性 - 可以是从抽象基类继承的类,而抽象基类又继承自
Entity
- 所有实例属性都有一个私有的 setter
- 所有类都有一个公共静态工厂方法
Create
,当然每个类的调用参数都不同
我想了解实体框架如何处理这种构造技术,它使用私有无参数构造函数来创建对象实例。
编辑2
我最终写出了一个解决方案,它与 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;
}