I define a struct:
public struct Settable
{
public string SettableProperty { get; set; }
}
I can set the value of the struct's property in the usual way:
s.SettableProperty = "Abc";
However, when I create a method to attempt to set the property by reflection:
public T CreateWithValue<T>(string propName, string propValue)
{
var retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
var _ = prop.SetMethod.Invoke(retObj, new object[] { propValue});
return retObj;
}
...and call it thus:
var x = CreateWithValue<Settable>("SettableProperty", "Abc");
...I end up with SettableProperty initialized to its default value, null. (No exception is thrown.)
Note that if I define Settable as a class instead of a struct, the value is set as expected.
Is it possible to set struct properties using reflection?
The problem here is that retObj is T, a value-type, but Invoke takes object. This boxes the value, which creates an isolated copy on the heap (inside the box), which you then mutate. Your local copy in retObj isn't impacted in any way here, since it is a completely disconnected copy of the value.
Consider instead:
public T CreateWithValue<T>(string propName, string propValue)
{
object retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
prop.SetMethod.Invoke(retObj, new object[] { typedValue });
return (T)retObj;
}
This creates the box earlier, and unboxes it to get the modified value. It is, however, not very efficient (note: I haven't added any inefficiency; the inefficiency is inherent when using an object API with a value-type). You can remove the allocations if you're happy to get much much dirtier.
Related
How can I set/get the value of an object in an object array?
Currently I get:
"object does not contain a definition for 'value' and no extension method"
Example C#;
public class myObjClass
{
public int value = 5;
}
public class myObjClass2
{
public float[] pos = new float[2];
}
public void test()
{
myObjClass myObj = new myObjClass();
myObjClass2 myObj2 = new myObjClass2();
object[] objArr = new object[2];
objArr[0] = myObj;
objArr[1] = myObj2;
Debug.Print(myObj.value.ToString());
Debug.Print(objArr[0].value.ToString()); // how?
}
Its because a generic object does not have the property value your class myObjClass has. To fix this you could cast the item to your class like so:
((myObjClass)objArr[0]).value.ToString()
Only do this ^ if you are sure of the type
Instead you could also check it first:
With as:
var item = objArr[0] as myObjClass;
if( item != null ) // Item will be null if its not a 'myObjClass'
{
//Do stuff with item
}
Or with is:
if( objArr[0] is myObjClass )
{
var item = (myObjClass)objArr[0];
//Do stuff with item
}
When using an object array you have to cast to the real type (here: myObjClass) before accessing the fields:
You can access the object like this
((myObjClass)objArr[0]).value
but I would not recommend. CanĀ“t you have your array to be the concrete type
var array = new myObjClass[42]
A compact safe alternative to retrieve the value is
(objArr[0] as myObjClass)?.value
You need to cast object to known type which is myObjClass, like:
((myObjClass)objArr[0]).value.ToString();
Or you can use reflection
var valueString = objArr[0].GetType().GetProperty("value").GetValue(objArr[0]);
Debug.Print(valueString.ToString());
Hope helps,
Technically you can put it as
Debug.Print((objArr[0] as myObjClass)?.value.ToString());
We try casting objArr[0] as myObjClass and if succeed get value and turn it to string. If objArr[0] is not myObjClass we return null as a string
However, a much better way is to implement ToString() in both classes of interest:
public class myObjClass
{
public int value = 5;
public override string ToString() {
// When debugging we want to know "value"
return value.ToString();
}
}
public class myObjClass2
{
public float[] pos = new float[2];
public override string ToString() {
// When debugging we want to know "pos[0]" and "pos[1]" values
return $"{pos[0]} : {pos[1]}";
}
}
And then put an easy
// Just print out debug info (we don't want to know the actual objArr[0] class)
Debug.Print(objArr[0].ToString());
You have a single object, that indeed is an instance of myObjClass, and has a value field, but you have two references to it.
One (myObj) is known to the compiler to be of type myObjClass, and it can guarantee that it has a value field.
The other (objArr[0]) is only known to the compiler to be of type object, and it cannot guarantee that it has a value field.
For example, you could do:
objArr[0] = (random.Next() > 0.5) : myObj ? myObj2
where we're gonna decide at runtime, based on the value of a random number, which will be the type of the actual object at objArr[0].
So, if this was allowed, half of the time objArr[0].value would be correct, and half of the time it will be an error.
I'm using a custom attribute to grab a property and then set it's value based on another object's value - I'm using reflection to get the attribute like this:
Class Property:
[MyPropertyName("MyString")]
string myString { get; set; }
Populating code:
public void PopulateMyPropertiesFromObject<T>(MyDataArrays dataArrays, T obj) where T : class, new()
{
Type type = typeof (T);
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
foreach (MyPropertyName propName in PropertyInfo.GetCustomAttributes(true).OfType<MyPropertyName>())
{
//Get the value from the array where MyPropertyName matches array item's name property
object value = GetValue(dataArrays, propName);
//Set the value of propertyInfo for obj to the value of item matched from the array
propertyInfo.SetValue(obj, value, null);
}
}
}
I have a collection of these data arrays and so I'm looping through them instantiating a new object of type T and calling this Populate method to populate the new T for each item in the collection.
What's bugging me is how much I'm looking up the MyPropertyName custom attribute because each call to this method will be passing in the same type for obj. on Average this will happen 25 times and then the object's type will change
Is there any way I can cache the properties with their MyPropertyName attribute?Then I'd just have a list of properties + MyPropertyNames to loop through
Or can I access the attributes in a nicer way than I am?
For context: this is all happening server side of an asp.net website, I've got roughly 200-300 objects, each with around 50 properties using the attribute above for the purposes of the method above
yes you can, you can use a static Dictionary
To do so safely, a lock period is required for accessing the dictionary.
To make it thread safe.
// lock PI over process , reflectin data is collected once over all threads for performance reasons.
private static Object _pilock = new Object();
private static Dictionary<string, PropertyInfo> _propInfoDictionary;
public PropertyInfo GetProperty(string logicalKey) {
// try from dict first
PropertyInfo pi;
// lock access to static for thread safety
lock (_pilock) {
if (_propInfoDictionary.TryGetValue(logicalKey, out pi)){
return pi;
}
pi = new PropertyInfo;
// set pi ...... do whatever it takes to prepare the object before saving in dictionary
_propertyInfoDictionary.Add(logicalKey, pi);
} // end of lock period
return pi;
}
SO Community,
So I'm learning C# and am still trying to wrap my head around reflection. In particular trying to use it to access a property of a property on a class.
I've boiled down the basic task that I'm trying to accomplish below:
public enum SIGNAL_STATE { NOT_RETRIEVED = 0, RETRIEVING = 1, RETRIEVED = 2, FAILED = 3 }
public class MyObjectClass
{
public string MyString;
private SIGNAL_STATE _state = SIGNAL_STATE.NOT_RETRIEVED;
public SIGNAL_STATE State { get { return _state; } set { _state = value;} }
}
public class NeedToReflect
{
private MyObjectClass _myObject1 = new MyObjectClass();
private MyObjectClass _myObject2 = new MyObjectClass();
private MyObjectClass _myObject3 = new MyObjectClass();
public MyObjectClass MyObject1
{
get{return _myObject1;}
set{_myObject1 = value;}
}
public MyObjectClass MyObject2
{
get{return _myObject2;}
set{_myObject2 = value;}
}
public MyObjectClass MyObject3
{
get{return _myObject3;}
set{_myObject3 = value;}
}
public static void Main(string [] args){
NeedToReflect needToReflect = new NeedToReflect();
string fieldName;
for(int idx = 1; idx<=3; ++idx)
{
fieldName = String.Format("MyObject{0}",idx);
//TODO: set state of 'MyObject' values to SIGNAL_STATE.RETRIEVING
}
}
}
edit 1:
At Yair Nevet's suggestion I'm grabbing the FieldInfo from the applicable object like,
FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
But from there I get hung up on accessing and setting the right 'State' Field/Property on that member field
Solution (ie. here's what I plugged in on that TODO comment):
// Determine what binding flags will give us proper access to our member field
BindingFlags bindFlags = BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance;
// Get the field for that field
FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, bindFlags);
// Pass in the containing object that we're reflecting on to get an instance of the member field
MyObjectClass myField = (MyObjectClass) fieldInfo.GetValue(needToReflect);
// We can now directly access and edit the value in question
myField.State = SIGNAL_STATE.RETRIEVING;
That does it. Thanks to Shlomi Borovitz for pointing me in the right direction.
Thanks!
The FieldInfo object which returned by GetField has property which called FieldInfo, which returns the type of that field.
And you can query it for that type's (the type of the field) properties/fields (and whatever you want) - and get/set them.
Remember that both GetType method (of any object), and the FieldInfo.FieldType property return Type object, that you can query in reflection.
object obj =...
var field = obj.GetType().GetField(fieldName,...);
field.FieldType.GetField(...
//etc... etc...
For each field, you can query the type and for each type, you can query the fields, and get/set them.
BTW, in C# 4.0 you can use the dynamic pseudo type (it used as a type when declaring dynamic variable, but it's not a real type), and then using that variable, while assuming which properties/fields/methods that variable would have in runtime (ie, using them like they are known in compile time although they don't).
This will not work for private members (and I can't warn you enough against calling private members in reflection), but for public members, this would make your code simple and readable, like you never used reflection (although, behind the scenes [in this case] reflection would be used).
You are trying to access a Property while the member is actually a private Field:
propertyName = String.Format("MyObject{0}",idx);
Use GetField method instead for that:
needToReflect.GetType().GetField(propertyName, BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance);
Go through these steps...
1) Get the Type.
2) Have an instance of that type.
3) Get the PropertyInfo for the property.
4) Call "GetSetMethod" on the PropertyInfo object. It will return a MethodInfo object.
5) Invoke the MethodInfo object using the instance of the type and a value.
Given:
class ClassyMcClass
{
public int PropertyB { get; set; }
}
class MyClass
{
public ClassyMcClass PropertyA { get; set; }
}
The following code uses reflection on a MyClass object to set the int value of PropertyB in PropertyA to NewValue:
PropertyInfo propA = typeof(MyClass).GetProperty("PropertyA");
PropertyInfo probBofA = propA.PropertyType.GetProperty("PropertyB");
// Set property B of property A, where obj is of type MyClass
probBofA.SetValue(propA.GetValue(obj), NewValue, null);
in my application that uses reflection i have two classes
public class FirstClass
{
public string someVar;
public SecondClass second;
public FirstClass()
{
second = new SecondClass();
}
}
public class SecondClass
{
public string anotherVar;
}
in my main program i have an instance of FirstClass
MainProgram()
{
Object obj = InstanceOfFirstClass() // reflected instance of first class
}
How do i set the value of anotherVar inside obj?
With public fields, this is relatively simple:
object obj = InstanceOfFirstClass();
object second = obj.GetType().GetField("second").GetValue(obj);
second.GetType().GetField("anotherVar").SetValue(second, "newValue");
If the fields were not public, then you would need to use an overload of GetField that takes a BindingFlags argument with the NonPublic flag set.
In .Net 4, you could just use dynamic:
dynamic obj = InstanceOfFirstClass();
obj.second.anotherVar = "newValue";
You can find the example which reads the field and set a value of the field via reflection in
http://msdn.microsoft.com/en-us/library/6z33zd7h.aspx.
In your case it will look like
Object myObject = InstanceOfFirstClass() // reflected instance of first class
Type myType = typeof(FirstClass);
FieldInfo myFieldInfo = myType.GetField("second",
BindingFlags.Public | BindingFlags.Instance);
// Change the field value using the SetValue method.
myFieldInfo.SetValue(myObject , //myobject is the reflected instance
value);//value is the object which u want to assign to the field);
I am trying to solve the following problem. We have an object of arbitrary structure and an array of strings representing field names. This array is a path that is used to retrieve specific fields using reflection. Then there is a value that should be stored in the final field. For example consider the following class hierarchy:
class A {
public int i;
}
class B {
public A a;
}
class C {
public B b;
}
class D {
public C c;
}
Let's say we get the input somehow:
object obj = GetObject(); // e.g. returns object of type D
List<string> path = GetPathToStore(); // e.g. returns {"c", "b", "a", "i"}
object value = GetValueToBeStored(); // e.g. returns 42
I wrote the following loop:
foreach (string fieldName in path) {
FileInfo fieldInfo = obj.GetType().GetField(fieldName);
obj = fieldInfo.GetValue(obj);
}
Then would be nice to have something like this:
obj = value;
But this will only change the reference and not the actual field in the object. In C++ I would write:
*obj = value;
but how to do this in C#?
I also need to support an edge case when the path is empty in which case the root object itself needs to be assigned a different value.
EDIT: My code actually uses more complex approach to retrieve members. Entries in the path are not necessarily field names, they could also be a property name, index in an array or List, key in a Dictionary etc. Therefore a class wrapping it would be complex. I am looking for a simpler solution.
Maybe something like this:
object obj = new D { c = new C { b = new B { a = new A { i = 1 } } } };
List<string> path = new List<string> { "c", "b", "a", "i" };
object value = 42;
FieldInfo fieldInfo = null;
object prevObj = null;
object obj2 = obj;
for (int i = 0; i < path.Count; i++)
{
string fieldName = path[i];
fieldInfo = obj2.GetType().GetField(fieldName);
if (i == path.Count - 1) prevObj = obj2;
obj2 = fieldInfo.GetValue(obj2);
}
if (fieldInfo != null)
{
fieldInfo.SetValue(prevObj, value);
}
Console.WriteLine(((D)obj).c.b.a.i == (int) value);
You can add the extra layer of indirection in a managed language, just as you can through pointer manipulation. In general, this is usually done through the use of a new class, since you can think of a class in general as a pointer to an object.
public class FieldWrapper
{
private object obj;
private FieldInfo field;
public FieldWrapper(object obj, FieldInfo field)
{
this.obj = obj;
this.field = field;
}
public object Value
{
get
{
return field.GetValue(obj);
}
set
{
field.SetValue(obj, value);
}
}
}
By holding onto the object instance and the FieldInfo object you can get and set the value of that object. This allows you to pass an instance of FieldWrapper around and just get/set the property and have it affect the underlying field of the object supplied in the constructor.
If you need something more generic you can rely on closures:
public class Wrapper
{
private Func<object> getter;
private Action<object> setter;
public Wrapper(Func<object> getter, Action<object> setter)
{
this.getter = getter;
this.setter = setter;
}
public object Value
{
get
{ return getter(); }
set
{ setter(value); }
}
}
Then to use it you could do something like this:
Wrapper pointer = new Wrapper(()=> fieldInfo.GetValue(obj)
, value => fieldInfo.SetValue(obj, value));
It takes a bit more work to create the objects, but has the same effect.
Another approach that you could take is to create a FieldWrapper, a PropertyWrapper, a DictionaryWrapper, etc. and have them all implement anIWrapperinterface that exposes aValue` so that once you create the wrapper you don't care what the underlying implementation is. That's a bit more work up front to create the wrapper for each type of object, but ends up taking less time to create each instance of the wrapped type.
I'm not sure if I understand your question correctly, but I think you want:
var fieldInfo = obj.GetType().GetField(fieldName);
fieldInfo.SetValue(obj, newValue);
EDIT: To support properties as well as fields, try:
foreach(var memberInfo in obj.GetType().GetMember(memberName))
{
if(memberInfo is FieldInfo)
{
((FieldInfo)memberInfo).SetValue(obj, newValue);
}
else if(memberInfo is PropertyInfo)
{
((PropertyInfo)memberInfo).SetValue(obj, newValue);
}
// etc ...
}
Not sure about how exactly you want to deal with indices, though. You CAN pass indices for indexed properties to PropertyInfo.SetValue().