Setting a field deep in the arbitrary object structure - c#

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().

Related

Why I can't assign dynamic data in constructor C#?

I'm a PHP Developer...
I need to do a class that can be created and fill of dynamic way, similar to this in PHP.
class Person{
private $name;
private $age;
function __construct($params = array()){
foreach ($this as $key => $val) {
$this -> $key = (isset($params[$key])) ? $params[$key] : "";
}
}
function getName(){
return $this->name;
}
function getAge(){
return $this->age;
}
function setName($value){
$this->name = $value;
}
function setAge($value){
$this->age = $value;
}
}
I read about the reflection in C#, but I don't find the correct way to do.
This is my C# code
public class Person
{
private String _name { get { return _name; } set { _name = value; } }
private int _age { get { return _age; } set { _age = value; } }
public Person()
{
}
public Person(Hashtable _data)
{
PropertyInfo[] propertyInfos;
propertyInfos = typeof(Person).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var propInfo in propertyInfos)
{
typeof(Person).GetProperty(propInfo.Name).SetValue(this, _data[propInfo.Name]);
}
}
}
In runtime I get an Exception
Object reference not set to an instance of an object.
The typeof(Person) I try to change it to this.getType() and I get the same.
I hope that can help me.
You are grabbing all properties on the object and then looking them up in the hashtable. You likely want the reverse--all objects in the hashtable set to properties on the object. Otherwise you'll get an exception when you don't specify every single member.
As Alexei points out, the NullReferenceException is due to the second call to GetProperties only returning public properties when no BindingFlags are supplied. Since there are no public properties, you get an exception.
Because C# is strongly typed, you run into a number of issues you don't have in PHP. These include setting a value with an object of a type that doesn't match or convert to the property type, entries in your data parameter that don't exist as properties, etc. I've done my best to document the gotchas I see below.
Here is what the Person class would look like (I've cleaned up some of the style and used classes to make it feel more like a C# class):
public class Person
{
private string name { get; set; }
private int age { get; set; }
public Person()
{
}
public Person(IDictionary<string,object> data)
{
foreach (var value in data)
{
// The following line will be case sensitive. Do you need to standardize the case of the input dictionary before getting the property?
PropertyInfo property = typeof(Person).GetProperty(value.Key, BindingFlags.Instance | BindingFlags.NonPublic);
if (property != null)
{
property.SetValue(this, value.Value); // You are allowing any old object to be set here, so be prepared for conversion and casting exceptions
}
else
{
// How do you want to handle entries that don't map to properties? Ignore?
}
}
}
}
And here is an example of usage:
static void Main(string[] args)
{
var person = new Person(new Dictionary<string,object>() {{"name" ,"Mike"}, {"age", 32}});
}
You should stay away from using var if you're new to the language, it only complicates things.
The propInfo in your foreach-loop already is a PropertyInfo, so you don't need to find it again:
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] propertyInfos = typeof(Person).GetProperties(flags);
foreach (PropertyInfo propInfo in propertyInfos)
{
propInfo.SetValue(this, _data[propInfo.Name]);
}
The NullReferenceException is probably caused by the following part of your original code:
typeof(Person).GetProperty(propInfo.Name)...
Since no BindingFlags are provided to the GetProperty() this time, it looks for public instance properties, and when no such property is found, it returns null (that, or _data is null to begin with).
As others have pointed out, your properties currently will cause StackOverflowExceptions. Try changing them to:
private String _name { get; set; }
private int _age { get; set; }
I am wondering why you would want to do this. There may be better, more idiomatic C#, designs to achieve the behavior you want. But we can't know that because there is no additional contextual information mentioned in the question.
So I will simply try to answer your question. The version below takes your code, using auto properties, and a simple dictionary lookup for the initialization of its members from the supplied dictionary. Also note that this does not require any reflection, because there is nothing dynamic about the members of this class.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(IDictionary<string, object> data)
{
// What to do if the map does not contain "Name" or "Age" ?
// Right now: initialize to default value.
Name = TryLookup<string>(data, "Name", null);
Age = TryLookup<int>(data, "Age", default(int));
// What to do if the map contains other items that do not
// map to a member variable?
}
private static T TryLookup<T>(IDictionary<string, object> data, string key, T defaultValue)
{
return data.ContainsKey(key) ? (T)data[key] : defaultValue;
}
}
In case you actually really really badly need a dynamic type as opposed to a statically defined type with fixed member properties, you could use an ExpandoObject or alternatively (but this is far from trivial) build a dynamic type using an AssemblyBuilder with a TypeBuilder

C# - Set Property of a Property with Reflection

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);

a function to set property values for several types of classes

I need a function with following signature in C# 4.0, I am lost where to start :
public static object SetStringPropertiesOnly(object obj)
{
//iterate all properties of obj
//if the type of the property is string,
//return obj
}
and eventually I want to use this function for my several objects derived from different classes:
myClass1 obj1 = new myClass1 ();
myClass2 obj2 = new myClass2 ();
.....
.....
obj1 = SetStringPropertiesOnly(obj1);
obj2 = SetStringPropertiesOnly(obj2);
So the type of the objects are dynamic here.
Is such a method possible?.
Thanks.
public static object SetStringPropertiesOnly(object obj)
{
//Get a list of properties where the declaring type is string
var stringProps = obj.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)).ToArray();
foreach (var stringProp in stringProps)
{
// If this property exposes a setter...
if (stringProp.SetMethod != null)
{
//Do what you need to do
stringProp.SetValue(obj, "value", null);
}
}
//What do you want to return?
return obj;
}
Consider changing your method signature to accept a value parameter and also change object obj to be ref, you don't need to return your object then.
I suppose you want to return the object itself.
However you should understand that the original object will also be changed.
public static object SetStringPropertiesOnly(object obj)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, "Value");
}
return obj;
}
My approach would be to make an extension method and return void, since the object would be changed. I also would add the wished string as a parameter.
public static void SetStringProperties(this object obj, string value)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, value);
}
return obj;
}
You can call the extension method like this:
obj.SetStringProperties("All strings will have this value");
By the way, the fact that you need to do this might be considered a "bad smelling code". Reconsider this design if you can.
Aint hard using reflection. And we can also do it as object extension (looks cute when you use it):
public static class ObjectExtensions
{
public static T SetStringPropertiesOnly<T>(this T obj) where T : class
{
var fields = obj.GetType().GetProperties();
foreach (var field in fields)
{
if (field.PropertyType == typeof (string))
{
field.SetValue(obj, "blablalba", null); //set value or do w/e your want
}
}
return obj;
}
}
and usage:
var obj = someObject.SetStringPropertiesOnly();
You could use a common interface, something in the lines of "IBulkStringEditable". The interface should contain a method "void SetStrings()".
Then all your classes have to implement this interface and the SetStrings method, where every class has different contents for SetStrings, depending on the string properties it has and the values you want them to have.
Then modify the SetStringPropertiesOnly function in this manner:
public static IBulkStringEditable SetStringPropertiesOnly(IBulkStringEditable obj)
{
obj.SetStrings();
return obj;
}
simply u can use dynamic in ur method parameter signature like that--->
public static object SetStringPropertiesOnly(dynamic obj)
{
// proceed
}

Create an Index Based Class in c# .Net

i've some classes and want to access their properties using index or something like
ClassObject[0] or better will be ClassObject["PropName"]
instead of this
ClassObj.PropName.
Thanks
You need indexers:
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx
public class MyClass
{
private Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
public object this[string key]
{
get { return _innerDictionary[key]; }
set { _innerDictionary[key] = value; }
}
}
// Usage
MyClass c = new MyClass();
c["Something"] = new object();
This is notepad coding, so take it with a pinch of salt, however the indexer syntax is correct.
If you want to use this so you can dynamically access properties, then your indexer could use Reflection to take the key name as a property name.
Alternatively, look into dynamic objects, specifically the ExpandoObject, which can be cast to an IDictionary in order to access members based on literal string names.
You can do something like this, a pseudocode:
public class MyClass
{
public object this[string PropertyName]
{
get
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
return pi.GetValue(this, null); //not indexed property!
}
set
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
pi.SetValue(this, value, null); //not indexed property!
}
}
}
and after use it like
MyClass cl = new MyClass();
cl["MyClassProperty"] = "cool";
Note that this is not complete solution, as you need to "play" with BindingFlags during reflection access if you want to have non public properties/fields, static ones and so on.
public string this[int index]
{
get
{ ... }
set
{ ... }
}
This will give you an indexed property. You can set any parameter you wish.
I'm not sure what you mean here, but I'll say that you have to make ClassObject some sort of IEnumirable type, like List<> or Dictionary<> to use it the way to aim for here.

Accessing an instance variable by name (string), kinda like dynamic languages do, in C#

i've got some C# code like this:
string fieldName = ...
string value = ...
if (fieldName == "a") a = value;
if (fieldName == "b") b = value;
if (fieldName == "c") c = value;
if (fieldName == "d") d = value;
...
I want something like this:
string fieldName = ...
string value = ...
SetMyInstanceVariable(fieldName, value);
...
Is there a simple way to do it?
I know that given a class's name in a string, you can instantiate it with System.Activator, and this is kindof similar so i was hoping....
A Dictionary<string, string> is the easiest approach:
public class Bag {
var props = new Dictionary<string, string>();
// ...
public string this[string key] {
get { return props[key]; }
set { props[key] = value; }
}
}
The reflection approach is considerably more complex but still doable:
public class Fruit {
private int calories = 0;
}
// ...
var f = new Fruit();
Type t = typeof(Fruit);
// Bind to a field named "calories" on the Fruit type.
FieldInfo fi = t.GetField("calories",
BindingFlags.NonPublic | BindingFlags.Instance);
// Get the value of a field called "calories" on this object.
Console.WriteLine("Field value is: {0}", fi.GetValue(f));
// Set calories to 100. (Warning! Will cause runtime errors if types
// are incompatible -- try using "100" instead of the integer 100, for example.)
fi.SetValue(f, 100);
// Show modified value.
Console.WriteLine("Field value is: {0}", fi.GetValue(f));
If they are properties in your class you can use:
this.GetType().GetProperty(fieldName).SetValue(this, value, null);
A field in the class
this.GetType().GetField(fieldName).SetValue(this, value, null);
You may need to alter binding flags based on the public/private status of the fields.
If they're just local variables to a function like you've described however I believe you may be out of luck.
It's by far preferable to use a datatype designed to be used in this way like a Dictionary, and perhaps you should consider replacing the existing variables with Properties that reference the dictionary. EG: string a { get { return myDictionary["a"]; } }. This may let you keep backwards compatibility without resorting to reflection, which really should be a last resort.
How about storing it all in a Dictionary<string, string>?

Categories

Resources