When loading data from external files (such as CSVs or configuration files) or dealing with dynamically determined keys, you often need to set object property values based on string names.
The SetValue method in Reflection is incredibly useful for this purpose. It allows you to write values to properties by specifying their names as strings at runtime, even if those names are unknown at compile time.
Setting Property Values Dynamically
The following sample code demonstrates how to populate an application configuration class (AppConfiguration) by specifying property names and values dynamically.
Sample Code
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
// 1. Create the target instance
var config = new AppConfiguration();
Console.WriteLine("--- Before Settings ---");
Console.WriteLine(config);
// 2. Set values using Reflection
// Normal assignment: config.Resolution = "1920x1080";
SetDynamicProperty(config, "Resolution", "1920x1080");
SetDynamicProperty(config, "MaxFrameRate", 60);
SetDynamicProperty(config, "EnableShadows", true);
// Test with a non-existent property name
SetDynamicProperty(config, "UnknownSetting", 123);
Console.WriteLine("\n--- After Settings ---");
Console.WriteLine(config);
}
/// <summary>
/// Sets a value to a property of a specified object
/// </summary>
/// <param name="target">Target object</param>
/// <param name="propertyName">Property name</param>
/// <param name="newValue">Value to set</param>
public static void SetDynamicProperty(object target, string propertyName, object newValue)
{
if (target == null) return;
// 1. Get object type information
Type type = target.GetType();
// 2. Get property information for the specified name
PropertyInfo propInfo = type.GetProperty(propertyName);
// Stop processing if the property does not exist
if (propInfo == null)
{
Console.WriteLine($"[Warning] Property '{propertyName}' does not exist.");
return;
}
// 3. Check if writable (does a setter exist?)
if (!propInfo.CanWrite)
{
Console.WriteLine($"[Warning] Property '{propertyName}' is not writable.");
return;
}
try
{
// 4. Set the value
// 1st arg: Target instance, 2nd arg: Value to set, 3rd arg: Index (usually null)
propInfo.SetValue(target, newValue);
Console.WriteLine($"[Success] Set {propertyName} to {newValue}.");
}
catch (ArgumentException)
{
Console.WriteLine($"[Error] Failed to set value for {propertyName} (Type mismatch, etc.).");
}
}
}
// Application Configuration Class
public class AppConfiguration
{
public string Resolution { get; set; } = "800x600"; // Resolution
public int MaxFrameRate { get; set; } = 30; // FPS
public bool EnableShadows { get; set; } = false; // Shadows
public override string ToString()
{
return $"[Config] Resolution:{Resolution}, FPS:{MaxFrameRate}, Shadows:{EnableShadows}";
}
}
Explanation and Technical Points
1. PropertyInfo.SetValue Method
By using the SetValue method on the PropertyInfo object obtained via GetProperty, you can invoke the setter of the target instance.
- Arguments: The basic form is
SetValue(object obj, object value). For indexed properties, a third argument is used. - Type Consistency: The type of the
valuepassed must be compatible with the property’s type. For example, trying to pass astringto anintproperty will throw anArgumentException(automatic type conversion is not performed).
2. Checking with the CanWrite Property
Some properties may only have a get accessor (read-only). By checking propInfo.CanWrite before calling SetValue, you can avoid errors caused by attempting to write to read-only properties.
3. Practical Use Case: Data Mappers
This technique is frequently used in the internal implementation of “Data Binding” and “O/R Mappers.” It allows libraries to map database query results (column names and values) or text data like JSON/XML directly to class properties.
