I am trying to get all properties of a class that have a private setter. This seems very simple, however I run into a strange, but probably normal, behavior.
This is the solution I have implemented
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;
}
I have created some simple classes for testing as well
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;
}
}
To test this I am using
[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);
}
The first test succeds while the second test fails. More specifically in second test, the code var allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
returns two properties however the property of the base class does not have a setter method. This is not properly coherent with the first test as in that case the property does have a set method which is defined as private.
Any suggestion/explanation about this behavior?
EDIT As per suggestions from comments I better explain the scope of the question. The final objective is to constructs some types of objects that have the following characteristics:
Entity
) which have a single unique instance property of type Guid with a private setterEntity
Create
with, of course, different parameters for each classI would like to understand how this construction technique is handled by Entity Framework which uses a private parameterless constructor to create object instances.
EDIT 2
I've ended up writing a solution which is very similar to the two presented by Jamiec and Gert Arnold. I am writing here for reference. Thanks everybody!
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;
}
This could be as easy as a bit of recursion, if the type has a base type, also add those properties to your list:
public static IEnumerable<PropertyInfo> InstanceProperties(this Type type)
{
List<PropertyInfo> results = new();
var allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var property in allProperties)
{
var setMethod = property.GetSetMethod(true);
if (setMethod != null && setMethod.IsPrivate)
{
results.Add(property);
}
}
if(type.BaseType != null)
{
results.AddRange(type.BaseType.InstanceProperties());
}
return results;
}
This gives your expected output of 2
in this specific example, but might need some tweaking to match your exact expectation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With