Search code examples
c#reflectionpropertiesread-write

How to iterate through all string properties and change their values using System.Reflection


I need to loop through all String properties of an item, retrieve their values, and manipulate the values - without needing to know the name of the item or property itself. So far, all the examples of SetValue that I've seen assume that you know the name of the property, and use that name to reference it. In my case, I'm not calling anything by name, but rather simply iterating through every string.

public class SpecialClass
{
    public string MyString1 { get; set; }
    public string MyString2 { get; set; }

    public void Sanitize()
    {
        Type CheckItemType = typeof(SpecialClass);
        Type strType = typeof(System.String);
        PropertyInfo[] propInfos = CheckItemType.GetProperties(
          BindingFlags.Public | BindingFlags.Instance);

        foreach (var propInfo in propInfos)
        {
            if (null != propInfo && propInfo.CanWrite)
            {
                if (propInfo.PropertyType == typeof(System.String))
                {
                    // Retrieve the value of the string, manipulate, and then set it

                }
            }
        }
    }
}

In the above code, the Sanitize method would loop through the strings in the class and adjust their values if they meet certain conditions.

While I found this post, what it describes seems to require that you know the name of the item and property. In my case, I don't know either. I have a Method whose purpose is to perform manipulation of all properties of type String.

I can't do this because I am working internally inside of the object - not referring to it externally - so I don't see how that could work.

I intuitively feel like this should be possible, but I can't quite put my head around the syntax of it.

An alternative would be to create this as a standalone function to which you ref an object, and it does the same type of thing, except in that scenario the object will have a name.


Solution

  • Once you have found a property you can write:

    string value = (string)propInfo.GetValue(this);
    // manipulate
    propInfo.SetValue(this, value);
    

    Hence the method can be:

    public void Sanitize()
    {
      var CheckItemType = typeof(SpecialClass);
      var strType = typeof(string);
      var propInfos = CheckItemType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
      foreach ( var propInfo in propInfos )
        if ( propInfo.PropertyType == strType && propInfo.CanWrite )
        {
          string value = (string)propInfo.GetValue(this);
          // manipulate
          propInfo.SetValue(this, value);
        }
    }
    

    You can also use Linq:

    public void Sanitize()
    {
      var typeString = typeof(string);
      var propertiesInfos = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                     .Where(p => p.PropertyType == typeString
                                              && p.CanWrite
                                              && p.CanRead);
      foreach ( var propertyInfo in propertiesInfos )
      {
        string value = (string)propertyInfo.GetValue(this);
        // manipulate
        propertyInfo.SetValue(this, value);
      }
    }
    

    Here we parse instance (this) properties, not static... so you can see the @DmitryBychenko answer to consider them and use null instead of this on static member by adding BindingFlags.Static to select them if needed.