Is there a way in C# where I can use reflection to set an object property?
Ex:
MyObject obj = new MyObject();
obj.Name = \"Value\";
Based on MarcGravell's suggestion, I have constructed the following static method.The method generically assigns all matching properties from source object to target using FastMember
public static void DynamicPropertySet(object source, object target)
{
//SOURCE
var src_accessor = TypeAccessor.Create(source.GetType());
if (src_accessor == null)
{
throw new ApplicationException("Could not create accessor!");
}
var src_members = src_accessor.GetMembers();
if (src_members == null)
{
throw new ApplicationException("Could not fetch members!");
}
var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
var src_class_propNames = src_class_members.Select(x => x.Name);
var src_propNames = src_members.Except(src_class_members).Select(x => x.Name);
//TARGET
var trg_accessor = TypeAccessor.Create(target.GetType());
if (trg_accessor == null)
{
throw new ApplicationException("Could not create accessor!");
}
var trg_members = trg_accessor.GetMembers();
if (trg_members == null)
{
throw new ApplicationException("Could not create accessor!");
}
var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
var trg_class_propNames = trg_class_members.Select(x => x.Name);
var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name);
var class_propNames = trg_class_propNames.Intersect(src_class_propNames);
var propNames = trg_propNames.Intersect(src_propNames);
foreach (var propName in propNames)
{
trg_accessor[target, propName] = src_accessor[source, propName];
}
foreach (var member in class_propNames)
{
var src = src_accessor[source, member];
var trg = trg_accessor[target, member];
if (src != null && trg != null)
{
DynamicPropertySet(src, trg);
}
}
}
You can try this out when you want to mass-assign properties of an Object from another Object using Property names:
public static void Assign(this object destination, object source)
{
if (destination is IEnumerable && source is IEnumerable)
{
var dest_enumerator = (destination as IEnumerable).GetEnumerator();
var src_enumerator = (source as IEnumerable).GetEnumerator();
while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
dest_enumerator.Current.Assign(src_enumerator.Current);
}
else
{
var destProperties = destination.GetType().GetProperties();
foreach (var sourceProperty in source.GetType().GetProperties())
{
foreach (var destProperty in destProperties)
{
if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }), new object[] { });
break;
}
}
}
}
You can also do:
Type type = target.GetType();
PropertyInfo prop = type.GetProperty("propertyName");
prop.SetValue (target, propertyValue, null);
where target is the object that will have its property set.
Yes, you can use Type.InvokeMember()
:
using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "Value");
This will throw an exception if obj
doesn't have a property called Name
, or it can't be set.
Another approach is to get the metadata for the property, and then set it. This will allow you to check for the existence of the property, and verify that it can be set:
using System.Reflection;
MyObject obj = new MyObject();
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
if(null != prop && prop.CanWrite)
{
prop.SetValue(obj, "Value", null);
}
Use somethings like this :
public static class PropertyExtension{
public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
{
PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null);
}
}
or
public static class PropertyExtension{
public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
{
PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
property.SetValue(p_object, safeValue, null);
}
}
I have just published a Nuget package that allows setting up not only the first level Properties but also nested properties in the given object in any depth.
Here is the package
Sets the value of a property of an object by its path from the root.
The object can be a complex object and the property can be multi level deep nested property or it can be a property directly under the root. ObjectWriter
will find the property using the property path parameter and update its value. Property path is the appended names of the properties visited from root to the end node property which we want to set, delimited by the delimiter string parameter.
Usage:
For setting up the properties directly under the object root:
Ie. LineItem
class has an int property called ItemId
LineItem lineItem = new LineItem();
ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);
For setting up nested property multiple levels below the object root:
Ie. Invite
class has a property called State
, which has a property called Invite
(of Invite type), which has a property called Recipient
, which has a property called Id
.
To make things even more complex, the State
property is not a reference type, it is a struct
.
Here is how you can set the Id property (to string value of “outlook”) at the bottom of the object tree in a single line.
Invite invite = new Invite();
ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");