This question already has answers here:
Get property value from string using reflection
(24 answers)
Closed 4 years ago.
What I'm trying to do is setting the value of the property in a class using a string. For example, my class has the following properties:
myClass.Name
myClass.Address
myClass.PhoneNumber
myClass.FaxNumber
All the fields are of string type so I know ahead of time that it's always a string. Now, I want to be able to set the properties using a string as you could do with a DataSet object. Something like this:
myClass["Name"] = "John"
myClass["Address"] = "1112 River St., Boulder, CO"
Ideally, I want to just assign a variable and then set the property using that string name from the variable:
string propName = "Name"
myClass[propName] = "John"
I was reading about reflection and maybe it's the way to do it but I'm not sure how to go about setting that up while keeping the property access intact in the class. I want to still be able to use:
myClass.Name = "John"
Any code examples would be really great.
You can add indexer property, a pseudocode:
public class MyClass
{
public object this[string propertyName]
{
get
{
// probably faster without reflection:
// like: return Properties.Settings.Default.PropertyValues[propertyName]
// instead of the following
Type myType = typeof(MyClass);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set
{
Type myType = typeof(MyClass);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
}
You can add an indexer to your class and use reflection to aces the properties:
using System.Reflection;
public class MyClass {
public object this[string name]
{
get
{
var properties = typeof(MyClass)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.Name == name && property.CanRead)
return property.GetValue(this, null);
}
throw new ArgumentException("Can't find property");
}
set {
return;
}
}
}
May be something like this?
public class PropertyExample
{
private readonly Dictionary<string, string> _properties;
public string FirstName
{
get { return _properties["FirstName"]; }
set { _properties["FirstName"] = value; }
}
public string LastName
{
get { return _properties["LastName"]; }
set { _properties["LastName"] = value; }
}
public string this[string propertyName]
{
get { return _properties[propertyName]; }
set { _properties[propertyName] = value; }
}
public PropertyExample()
{
_properties = new Dictionary<string, string>();
}
}
Related
I'm experimenting with reflection in c# for the first time (for use in a dev tool I'm building) and I was wondering if someone could help me to access the thing that I'm trying to access?
The code below is the class I'm accessing:
[Serializable]
public class MaterialVariantTarget : BaseNode, IMaterialTarget
{
public MeshRenderer m_Target;
public void ApplyValue(Material value) => m_Target.material = value;
}
The question I want to answer is what is the name of the value that ApplyValue() operate on. So in this example it would be MeshRenderer.material
I've broken the problem down into two parts. Accessing m_Target's Type (MeshRenderer) and the .material property.
The first, I've managed to access:
private Type GetTargetComponentType(Type targetNodeType)
{
foreach (var fieldInfo in targetNodeType.GetFields())
{
if (fieldInfo.Name == "m_Target")
{
var type = fieldInfo.FieldType;
return type;
}
}
return null;
}
I'm finding accessing the scond part more tricky. Is what I'm trying to do even possible and if so, how can I do it?
Many Thanks
[UPDATE]
So the consensus seems to be that I can't access the contents of the method.
I'm going to have to just resort to writing out the info I need as a string hich can then be read but its not ideal :(
Might I have more options if I were to arrange it as a property get/setter? like this:
[Serializable]
public class MaterialVariantTarget : BaseNode, IMaterialTarget
{
public MeshRenderer m_Target;
private Material m_valueProperty
{
get => m_Target.material;
set => m_Target.material = value;
}
public void ApplyValue(Material value) => m_valueProperty = value;
}
Here's two handy extensions I made to retrieve the value of a field or property of an object based on a name or a type:
public static class Extensions
{
public static object GetPropertyOrFieldByName(this object obj, string nameToSearch)
{
foreach (var field in obj.GetType().GetFields())
{
if (field.Name == nameToSearch)
{
return field.GetValue(obj);
}
}
foreach (var property in obj.GetType().GetProperties())
{
if (property.Name == nameToSearch)
{
return property.GetValue(obj);
}
}
return null;
}
public static T GetPropertyOrFieldByType<T>(this object obj) where T : Object
{
foreach (var field in obj.GetType().GetFields())
{
if (field.FieldType == typeof(T))
{
return (T)field.GetValue(obj);
}
}
foreach (var property in obj.GetType().GetProperties())
{
if (property.PropertyType == typeof(T))
{
return (T)property.GetValue(obj);
}
}
return null;
}
}
The usage you require could be implemented this way:
object target = yourMaterialVariantTarget.GetPropertyOrFieldByName("m_Target");
Material material = target.GetPropertyOrFieldByType<Material>();
material.color = Color.red;
is there a way to get the value of a property of a object based on its name?
For example if I have:
public class Car : Vehicle
{
public string Make { get; set; }
}
and
var car = new Car { Make="Ford" };
I want to write a method where I can pass in the property name and it would return the property value. ie:
public string GetPropertyValue(string propertyName)
{
return the value of the property;
}
return car.GetType().GetProperty(propertyName).GetValue(car, null);
You'd have to use reflection
public object GetPropertyValue(object car, string propertyName)
{
return car.GetType().GetProperties()
.Single(pi => pi.Name == propertyName)
.GetValue(car, null);
}
If you want to be really fancy, you could make it an extension method:
public static object GetPropertyValue(this object car, string propertyName)
{
return car.GetType().GetProperties()
.Single(pi => pi.Name == propertyName)
.GetValue(car, null);
}
And then:
string makeValue = (string)car.GetPropertyValue("Make");
You want Reflection
Type t = typeof(Car);
PropertyInfo prop = t.GetProperty("Make");
if(null != prop)
return prop.GetValue(this, null);
Expanding on Adam Rackis's answer - we can make the extension method generic simply like this:
public static TResult GetPropertyValue<TResult>(this object t, string propertyName)
{
object val = t.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(t, null);
return (TResult)val;
}
You can throw some error handling around that too if you like.
In addition other guys answer, its Easy to get property value of any object by use Extension method like:
public static class Helper
{
public static object GetPropertyValue(this object T, string PropName)
{
return T.GetType().GetProperty(PropName) == null ? null : T.GetType().GetProperty(PropName).GetValue(T, null);
}
}
Usage is:
Car foo = new Car();
var balbal = foo.GetPropertyValue("Make");
Simple sample (without write reflection hard code in the client)
class Customer
{
public string CustomerName { get; set; }
public string Address { get; set; }
// approach here
public string GetPropertyValue(string propertyName)
{
try
{
return this.GetType().GetProperty(propertyName).GetValue(this, null) as string;
}
catch { return null; }
}
}
//use sample
static void Main(string[] args)
{
var customer = new Customer { CustomerName = "Harvey Triana", Address = "Something..." };
Console.WriteLine(customer.GetPropertyValue("CustomerName"));
}
To avoid reflection you could set up a Dictionary with your propery names as keys and functions in the dictionary value part that return the corresponding values from the properties that you request.
2 Very short options, 1 with a default value if it fails:
public object GetPropertyValue_WithDefault(
object _t,
string _prop,
object _default = null
)
{
PropertyInfo pi = _t.GetType().GetProperty(_prop);
return (pi == null
? _default
: pi.GetValue(_t, null)
);
}
public object GetPropertyValue(object _t, string _prop)
{
//because of "?." will return null if property not found
return _t.GetType().GetProperty(_prop)?.GetValue(_t, null);
}
I need to read the attribute of a property using reflection
For example I get the following :
[XmlElement("Id")]
[CategoryAttribute("Main"), ReadOnly(true),
Description("This property is auto-generated")]
[RulesCriteria("ID")]
public override string Id
{
get { return _ID; }
set
{
_ID = value;
}
}
i want to get the " read only "value of this property using reflection
can anybody help
It's difficult to write the code for your case without knowing the Type name. Hope below example helps.
using System;
using System.Reflection;
public class Myproperty
{
private string caption = "Default caption";
public string Caption
{
get{return caption;}
set {if(caption!=value) {caption = value;}
}
}
}
class Mypropertyinfo
{
public static int Main(string[] args)
{
Console.WriteLine("\nReflection.PropertyInfo");
// Define a property.
Myproperty Myproperty = new Myproperty();
Console.Write("\nMyproperty.Caption = " + Myproperty.Caption);
// Get the type and PropertyInfo.
Type MyType = Type.GetType("Myproperty");
PropertyInfo Mypropertyinfo = MyType.GetProperty("Caption");
// Get and display the attributes property.
PropertyAttributes Myattributes = Mypropertyinfo.Attributes;
Console.Write("\nPropertyAttributes - " + Myattributes.ToString());
return 0;
}
}
MSDN
public static bool PropertyReadOnlyAttributeValue(PropertyInfo property)
{
ReadonlyAttribute attrib = Attribute.GetCustomAttribute(property, typeof(ReadOnlyAttribute));
return attrib != null && attrib.IsReadOnly;
}
public static bool PropertyReadOnlyAttributeValue(Type type, string propertyName)
{
return PropertyReadOnlyAttributeValue(type.GetProperty(propertyName));
}
public static bool PropertyReadOnlyAttributeValue(object instance, string propertyName)
{
if (instance != null)
{
Type type = instance.GetType();
return PropertyReadOnlyAttributeValue(type, propertyName);
}
return false;
}
I have a method where I am passing in two object, which have the same property names, and I'm using Reflection to get the values from one object and set the values on the other. My problem is when I come across a property that is a collection, the original is EntityCollection and the one getting set is ObservableCollection, and I'm obviously going to throw a casting error when I try to set the value.
So how would I go about this? I thought one way would be to get the instance of the EntityCollection property and in a loop use Activator.CreateInstance() to add a new item to the ObservableCollection. But I come across another question of how to get the original instance.
I would be greatly appreciative for some insight into this dilemma. I'll post the code for the method that I'm working with. It currently doesn't work, mainly I posted it just for a reference. So please don't point out the obvious. Thanks in advance.
protected void SetValues(Object thisObject, Object entity)
{
PropertyInfo[] properties = entity.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
var value = property.GetValue(entity, null);
var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name);
if (thisObjectsProperty != null && value != null)
{
if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0)
{
Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0];
Type entityCollectionType = property.PropertyType;
Type thisCollectionType = thisObjectsProperty.PropertyType;
IList entityCollection = (IList)Activator.CreateInstance(entityCollectionType.MakeGenericType(genericType));
IList observableCollection = (IList)Activator.CreateInstance(thisCollectionType.MakeGenericType(genericType));
foreach (var item in entityCollection)
{
String typeString = String.Concat("RulesGenerator.DependencyObjects.", genericType.Name);
Type newItemType = Type.GetType(typeString, false, true);
if (newItemType != null)
{
var newItem = Activator.CreateInstance(newItemType);
SetValues(newItem, item);
observableCollection.Add(newItem);
}
}
}
else
thisObjectsProperty.SetValue(thisObject, value, null);
}
}
}
Implement the ICloneable interface to provide a deep copy. You should be able to find some examples, but here is a starting point:
http://msdn.microsoft.com/en-us/library/system.icloneable%28v=VS.71%29.aspx
http://en.csharp-online.net/ICloneable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class testMain : ICloneable
{
private string m_TestProp;
private List<Record> m_Items = new List<Record>();
public string TestProp
{
get { return m_TestProp; }
set { m_TestProp = value; }
}
public List<Record> Items
{
get { return m_Items; }
}
public object Clone()
{
testMain cpy =(testMain) this.MemberwiseClone();
foreach (Record rec in this.Items)
{
Record recCpy = (Record)rec.Clone();
cpy.Items.Add(recCpy);
}
return cpy;
}
}
public class Record : ICloneable
{
private string m_TestProp;
public string TestProp
{
get { return m_TestProp; }
set { m_TestProp = value; }
}
public object Clone()
{
return this.MemberwiseClone();
}
}
public class CustomProperty<T>
{
private T _value;
public CustomProperty(T val)
{
_value = val;
}
public T Value
{
get { return this._value; }
set { this._value = value; }
}
}
public class CustomPropertyAccess
{
public CustomProperty<string> Name = new CustomProperty<string>("cfgf");
public CustomProperty<int> Age = new CustomProperty<int>(0);
public CustomPropertyAccess() { }
}
//I jest beginer in reflection.
//How can access GetValue of CPA.Age.Value using fuly reflection
private void button1_Click(object sender, EventArgs e)
{
CustomPropertyAccess CPA = new CustomPropertyAccess();
CPA.Name.Value = "lino";
CPA.Age.Value = 25;
//I did like this . this is the error “ Non-static method requires a target.”
MessageBox.Show(CPA.GetType().GetField("Name").FieldType.GetProperty("Value").GetValue(null ,null).ToString());
}
How about a method like this:
public Object GetPropValue(String name, Object obj) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
And use it like so:
Object val = GetPropValue("Age.Value", CPA);
Read the error message.
Non-static methods and properties are associated with an instance of a class - and so you need to provide an instance when trying to access them through reflection.
In the GetProperty.GetValue method, you need to specify the object for which you want to get the property value. In your case, it would be: GetValue(CPA ,null)