Field substring field FieldInfo field

Good afternoon,

I need to make a function that will iterate over a dictionary that stores the name of the variable and the new value of the variable. After that I need to update the class variable with this value.

void UpdateValues(Type type, Dictionary<string, string> values) { foreach (var value in values) { var fieldInfo = selected.GetComponent(type).GetType().GetField(value.Key); if (fieldInfo == null) continue; fieldInfo.SetValue(selected.GetComponent(type), value.Value); } } 

This works, but I want to improve a little, and I absolutely do not know if this is possible. As you can see, this function can take any class, and not just one specific one.

If I have a class like this

 class test { public string age; } 

And I would use the function this way, it would work.

 UpdateValues(typeof(test), new Dictionary<string, string>{{"age", "17"}}); 

The problem is that I have a class like this and I would like to update the "subfield" (field in field)

 class test { public string age; } class test2 { public test data; } 

I thought the syntax might be something like this, but I have no idea how I can do this.

 UpdateValues(typeof(test2), new Dictionary<string, string>{{"data.age", "17"}}); 

To summarize, I need to create a function that will take a class that is stored in another class. The function will iterate through the dictionary and update the fields of the class and even its subfields.

+6
source share
2 answers

I would suggest adding a recursive call to your method to set properties. I changed my method a bit because I don’t have a selected object, it takes an object as a parameter

 void UpdateValues<T>(T obj, Dictionary<string, string> values) { foreach (var value in values) { SetProperty(obj, value.Key, value.Value); } } public void SetProperty<T>( T obj, string valueKey, string value, Type type= null) { var typeToUse = type ?? typeof(T); var pointIndex = valueKey.IndexOf("."); if (pointIndex!=-1) { var subKey = valueKey.Substring(0, pointIndex); var fieldInfo = typeToUse.GetField(subKey); var propObj = fieldInfo.GetValue(obj) ?? Activator.CreateInstance(fieldInfo.FieldType); SetProperty(propObj, valueKey.Substring(pointIndex+1), value, fieldInfo.FieldType); fieldInfo.SetValue(obj, propObj); } else { var fieldInfo = typeToUse.GetField(valueKey); if (fieldInfo != null) fieldInfo.SetValue(obj, value); } } 

It works even if you define

 class test3 { public test2 data; } 

and call

 UpdateValues(t, new Dictionary<string, string>{{"age", "17"}}); UpdateValues(t2, new Dictionary<string, string> { { "data.age", "17" } }); UpdateValues(t3, new Dictionary<string, string> { { "data.data.age", "17" } }); 

The third parameter of the SetProperty method is not very pleasant, I would have avoided it, but I don’t know how to solve it using generics, after creating with Activator you get object as a type, and the object does not have an age field

You use Dictionary<string, string> as a parameter that allows you to set only string fields, so you should assume that you have no other. Actually, this will work even if you use Dictionary<string, object> , which I would suggest to do.

+1
source

First of all, you need to change the Dictionary variable to use Dictionary<string, object> if you want to pass the class as a parameter here. Secondly, here is an example of how to make it work.

 class test { public string age; } class test2 { public test data; } 

Suppose I created an instance of the test class and added it to the dictionary to get reflection fields, and then update the test2 instance accordingly.

  public void UpdateValues(object test2, Dictionary<string, object> dict) { var fieldValues = test2.GetType() .GetFields() .ToList(); foreach (var value in dict) { foreach (var field in fieldValues) { if (value.Key == field.Name) { bool obj = field.FieldType == typeof(test); if (obj) { if (dict.ContainsKey("data")) { var prop = test2.GetType().GetField("data", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); prop.SetValue(test2, dict["data"]); break; } } else { var prop = test2.GetType().GetField(value.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); prop.SetValue(test2, value.Value); break; } } } } } 

At the end of the function call, you created an instance of Dictionary<string,object> to send it as a function parameter

  object test2 = new test2(); test t = new test(); t.age = "10"; Dictionary<string, object> dict = new Dictionary<string, object>(); dict.Add("data", t); UpdateValues(test2, dict); 
0
source

Source: https://habr.com/ru/post/1013459/


All Articles