2016-12-23 12 views
6

Dobry dzień,Podpole aktualizacji FieldInfo pola

Potrzebuję funkcji, która będzie iterować na słownika, który przechowuje nazwę zmiennej i nową zmienną zmiennej. Następnie muszę zaktualizować zmienną klasy o tę wartość.

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

Działa, ale chcę niewielkiej poprawy i absolutnie nie wiem, czy to możliwe. Jak widać, ta funkcja może akceptować dowolną klasę, a nie tylko jedną konkretną.

Jeśli mam klasy jak ten

class test 
{ 
    public string age; 
} 

I chciałbym korzystać z funkcji w ten sposób, że będzie działać.

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

Problem jest, jeśli mam klasy jak ten i chciałbym zaktualizować „podpole” (pole w polu)

class test 
{ 
    public string age; 
} 

class test2 
{ 
    public test data; 
} 

Myślałam, że składnia może być coś takiego, ale mam nie mam pojęcia, jak mogłem to zrobić.

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

Podsumowując, muszę zrobić funkcję, która będzie miała klasę, który jest przechowywany w innej klasie. Funkcja będzie iterować przez słownik i aktualizować pola klasy, a nawet jej subpola.

Odpowiedz

1

Chciałbym zaproponować dodanie wywołania rekursywnego do metody, aby ustawić właściwości. Zmieniłem metoda trochę, bo nie mam selected obiektu, zajmuje obiekt jako parametr

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

To działa nawet jeśli zdefiniować

class test3 
{ 
    public test2 data; 
} 

i nazywają

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

Trzeci parametr metody SetProperty nie jest zbyt dobry, uniknęłbym go, ale nie wiem jak go rozwiązać za pomocą generycznych, po utworzeniu z Activator masz object jako typ, a obiekt nie ma pole age

Używasz Dictionary<string, string> jako parametr, który pozwala ustawić tylko pola ciągów, więc należy przyjąć, że nie ma innych. Właściwie to zadziała, nawet jeśli użyjesz Dictionary<string, object>, co proponuję zrobić.

+0

absolutnie ogromne dzięki :) wszystko działa, będę dostosować szczegóły – Mrgnito

0

Przede wszystkim należy zmienić zmienną Dictionary, aby użyć Dictionary<string, object>, jeśli chcesz przekazać klasę jako parametr tutaj. Po drugie Oto przykład, jak to zrobić.

class test 
{ 
    public string age; 
} 

class test2 
{ 
    public test data; 
} 

Pozwala Załóżmy, że stworzyliśmy instancję test klasy i dodać go w słowniku, aby pola z refleksji, a następnie zaktualizować instancję test2 odpowiednio.

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

     } 
    } 

W końcu zadzwonić ty funkcjonować i stworzyliśmy instancję Dictionary<string,object> wysłać go jako parametr do funkcji

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); 
Powiązane problemy