Reputation: 27220
I'm trying to reflect over some class properties and set them programmatically, but it looks like one of my PropertyInfo filters isn't working:
//Get all public or private non-static properties declared in this class (no inherited properties) - that have a getter and setter.
PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.SetProperty );
I'm getting an error on the line
pi.SetValue(this, valueFromData, null);
Because the property has only a get{}
method, no set{}
method.
My question is, why wasn't this property filtered out of props? I thought that was the purpose of BindingFlags.SetProperty.
The property not getting filtered out is:
public String CollTypeDescription
{
get { return _CollTypeDescription; }
}
Note that I want to filter properties that won't work ahead of time because I'm listing them all at once. I don't want to use pi.GetSetMethod()
after the fact to determine whether I can use the setter.
Upvotes: 45
Views: 48215
Reputation: 189
I use this code:
public class CustomBinder
{
public static void BindModel(object myClass)
{
var stringItems = myClass?.GetType()
.GetProperties()
.Where(x => x.PropertyType == typeof(string)).ToList();
if (!(stringItems?.Count > 0)) return;
foreach (var propertyInfo in stringItems)
{
if (propertyInfo.GetValue(myClass, null) != null)
{
var val = propertyInfo.GetValue(myClass).ToString().Replace(...);
if(propertyInfo.CanWrite)
propertyInfo.SetValue(myClass, val);
}
}
}
public static void BindModel(List<string> listString)
{
if (!(listString?.Count > 0 )) return;
for (var i = 0; i < listString.Count; i++)
listString[i] = listString[i].Replace(...);
}
}
Upvotes: 0
Reputation: 27220
Thanks to ken for the information. It looks like the best solution I can get it to filter them out by testing GetSetMethod(true) in a LINQ filter:
// Get all public or private non-static properties declared in this class
// (e.g. excluding inherited properties) that have a getter and setter.
PropertyInfo[] props = this.GetType()
.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic)
.Where(p => p.GetGetMethod(true) != null && p.GetSetMethod(true) != null)
.ToArray();
Alternatively, using CanRead
and CanWrite
:
PropertyInfo[] props = this.GetType()
.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.NonPublic)
.Where(p => p.CanRead && p.CanWrite)
.ToArray();
It's unclear to me whether these different approaches will yield different results for different protection levels of the get/set methods.
Upvotes: 7
Reputation: 4371
I understand the GetProperties() method so that it returns every property that has BindingFlags.GetProperty
or BindingFlags.SetProperty
.
So if you want only properties that have setters you must remove the BindingFlags.GetProperty
flag. But I did not tested it so I can be wrong.
My answer got a -1. So it seems that my answer is wrong.
Upvotes: -1
Reputation: 17574
From the documentation:
BindingFlags.SetProperty
Specifies that the value of the specified property should be set. For COM properties, specifying this binding flag is equivalent to specifying PutDispProperty and PutRefDispProperty.
BindingFlags.SetProperty
and BindingFlags.GetProperty
do not filter properties that are missing setters or getters, respectively.
To check if a property can be set, use the CanWrite
property.
if (pi.CanWrite)
pi.SetValue(this, valueFromData, null);
Upvotes: 87