Setting a property by reflection with a string value
You can use Convert.ChangeType()
- It allows you to use runtime information on any IConvertible
type to change representation formats. Not all conversions are possible, though, and you may need to write special case logic if you want to support conversions from types that are not IConvertible
.
The corresponding code (without exception handling or special case logic) would be:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Set object property using reflection
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);
}
Get property value from string using reflection
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Of course, you will want to add validation and whatnot, but that is the gist of it.
Set property value with reflection
You don’t need to do it that complicated. Once you have extracted the settings object, you can just update that:
PropertyInfo settingsProperty = viewModel.GetType().GetProperty("Settings");
Settings settings = (Settings) settingsProperty.GetValue(viewModel);
settings.A = "Foo";
settings.B = true;
settings.C = 123;
This is already enough to change the settings stored in the view model. If Settings
is a value type, you will have to write the changed settings object back to the object, like this:
settingsProperty.SetValue(viewModel, settings);
But that’s really all you will have to do. Of course, if you know that viewModel
is of type VM
, you can just type-cast it, and access the property directly:
Settings settings = ((VM)viewModel).Settings;
So instead of using reflection, a much better way would be to define some base type, or an interface, that has the Settings
property and make your view models implement that:
public interface HasSettings
{
Settings Settings { get; set; }
}
public class VM : HasSettings
{ … }
That way, your method can accept a HasSettings
object instead of a plain object
, and you can just access the settings object directly:
public void Init (HasSettings viewModel)
{
viewModel.Settings.A = "Foo bar";
}
If you have different Settings
types with different properties, and you want to run reflection on those too, then you can do that as well:
PropertyInfo settingsProperty = viewModel.GetType().GetProperty("Settings");
object settings = settingsProperty.GetValue(viewModel);
for (PropertyInfo prop in settings.GetType().GetProperties())
{
object value = GetValueForPropertyName(prop.Name); // magic
prop.SetValue(settings, value);
}
Again, no need to write the settings object back unless it’s a value type.
Using reflection to set a property of a property of an object
Basically split it into two property accesses. First you get the myClass1Object
property, then you set the value
property on the result.
Obviously you'll need to take whatever format you've got the property name in and split it out - e.g. by dots. For example, this should do an arbitrary depth of properties:
public void SetProperty(object source, string property, object target)
{
string[] bits = property.Split('.');
for (int i=0; i < bits.Length - 1; i++)
{
PropertyInfo prop = source.GetType().GetProperty(bits[i]);
source = prop.GetValue(source, null);
}
PropertyInfo propertyToSet = source.GetType()
.GetProperty(bits[bits.Length-1]);
propertyToSet.SetValue(source, target, null);
}
Admittedly you'll probably want a bit more error checking than that :)
Reflection: Get/Set Value of Property's PropertyType's Property
Modified your code, sure I have no running code but concept should be clear to you:
public void insertAllFromVariable(GameObject target, List<Type> types, string propertyName)
{
var components = target.GetComponents<Component>();
foreach (var component in components)
{
if (types.Contains(component.GetType()))
{
PropertyInfo property = component.GetType().GetProperty(propertyName);
object theRealObject = property.GetValue(component);
PropertyInfo[] propertysProperties = theRealObject.GetType().GetProperties().Where(t => t.GetCustomAttributes<ListableAttribute>().Count() > 0);
foreach (PropertyInfo p in propertysProperties)
{
Debug.Log("VALUE: " + p.GetValue(theRealObject));
C# Reflection - SetValue by path to property
I think your original version will end up setting the value "one level too deep".
I think a recursive pattern would be easier to follow, and require less code. Here is a quick version that I threw together that works on simple test cases.
There are several opportunities for optimizations (rebuilding the string on the recursive call), and edge cases (like null
checks) that I don't have the time to handle right now, but I don't think they will be too hard to add.
public void SetProperty(object target, string property, object setTo)
{
var parts = property.Split('.');
var prop = target.GetType().GetProperty(parts[0]);
if (parts.Length == 1)
{
// last property
prop.SetValue(target, setTo, null);
}
else
{
// Not at the end, go recursive
var value = prop.GetValue(target);
SetProperty(value, string.Join(".", parts.Skip(1)), setTo);
}
}
Here is a LINQPad demo showing it in action:
void Main()
{
var value = new A();
Debug.WriteLine("Original value:");
value.Dump();
Debug.WriteLine("Changed value:");
SetProperty(value, "B.C.D","changed!");
value.Dump();
}
public void SetProperty(object target, string property, object setTo)
{...}
public class A
{
public B B { get; set; } = new B();
}
public class B
{
public C C { get; set; } = new C();
}
public class C
{
public string D { get; set; } = "test";
}
It produces the following results:
Change property value
replace this code :
you should pass instance of object to getValue() or setValue() not property
public static T LocalTime<T>(T value, string locationTimeZone)
{
if (value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>))
{
IList collection = (IList)value;
foreach (var element in collection)
{
PropertyInfo[] props = element.GetType().GetProperties();
foreach (var property in props)
{
if (property.PropertyType == typeof(System.DateTime?))
{
var localTime = LocalTimeConvert("Alaskan Standard Time", DateTime.Now);
property.SetValue(element, localTime);
}
else if (property.PropertyType == typeof(System.DateTime))
{
property.SetValue(element, ((System.DateTime)property.GetValue(element, null)).AddDays(10), null);
}
}
}
}
return value;
}
Cast a value and set a property using reflection
See SetValue method. You should swap value
and object
parameters:
_propertyInfo.SetValue(Element, value, null);
How get inner property value by reflection
Instead of using var, you can force the type of aa to be a dynamic.
dynamic aa = propertyInfo.GetValue(Rating, null);
return aa.from;
Related Topics
How to Enable Cors in ASP.NET Core Webapi
Resizing an Image Without Losing Any Quality
Will Using 'Var' Affect Performance
How to Do Constructor Chaining in C#
Maximum Number of Threads in a .Net App
How to Tell Whether a Point Is to the Right or Left Side of a Line
Distinct Not Working With Linq to Objects
How to Use C# 7 With Visual Studio 2015
Inconsistent Accessibility: Parameter Type Is Less Accessible Than Method
Getting Multiple Keys of Specified Value of a Generic Dictionary
Desktop Applicaton Not Opening After Installation in Client System
How to Secure an ASP.NET Web API
Unsubscribe Anonymous Method in C#
Is It Better to Return Null or Empty Collection
A Potentially Dangerous Request.Path Value Was Detected from the Client (*)