简体   繁体   中英

set properties of data class using reflection in constructor

I have several data classes defined in a similar way to the below and am trying to decide whether to have a built-in constructor for each data class to populate the members, or use reflection only once in the calling method:

public class reportData
{

public List<Deposits> Deposits;
}

public class Deposits
{
    public Deposits(List<Dictionary<string, string>> LPQReq)
    {
        PropertyInfo[] properties = typeof(Deposits).GetProperties();

        foreach (Dictionary<string, string> PQList in LPQReq)
        {
            foreach (KeyValuePair<string, string> kvp in PQList)
            {
                MemberInfo info = typeof(Deposits).GetField(kvp.Key) as MemberInfo ?? typeof(Deposits).GetProperty(kvp.Key) as MemberInfo;

                //PropertyInfo property = properties[kvp.Key];

                // info.setvalue
            }
        }
        foreach (PropertyInfo property in properties)
        {
            Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(typeof(Deposits), null));
        }
    }
    public string YPBRNO { get; set; }
    public string YPBNA { get; set; }
    public string YPTME { get; set; }
... cut for brevity

I would like to use reflection to have my constructor take a list of Dictionary key-value pairs, and the key matches the name of the property...

then I can just use something like

PropertyInfo property = properties[kvp.Key];

or

info.setValue(typeof(Deposits), value, null);

one way of course is to loop through all the properties in my type and check if the property.name=kvp.key before calling setValue() like so:

        foreach (Dictionary<string, string> PQList in LPQReq)
        {
            foreach (KeyValuePair<string, string> kvp in PQList)
            {
                MemberInfo info = typeof(Deposits).GetField(kvp.Key) as MemberInfo ?? typeof(Deposits).GetProperty(kvp.Key) as MemberInfo;

                //PropertyInfo property = properties[kvp.Key];

                // info.setvalue
                foreach (PropertyInfo property in properties)
                {
                    if (property.Name==kvp.Key)
                    {
                        property.SetValue(typeof(Deposits), kvp.Value, null);
                    }
                    Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(typeof(Deposits), null));
                }
            }
        }

so now I have got that far, is it a good idea to do it this way, inside the constructor of each class (that I must then invoke externally)

or should I use the reflection in the calling method to set all the properties without having to know what the properties are...like this (this happens in a loop) :

Type target = Type.GetType(DocumentType);
foreach (Dictionary<string, string> PQList in LPQReq)
{
    foreach (KeyValuePair<string, string> kvp in PQList)
    {
        PropertyInfo prop = target.GetProperty(kvp.Key);

        prop.SetValue (target, kvp.Value, null);
        }

        Console.WriteLine("Template Name = {0}", templateName);
        }

EDIT:

Just wanted to mention I did read SO 1044455: c-sharp-reflection-how-to-get-class-reference-from-string to find out how to return the data class just from a name ...

so I initially thought I would use the reflection outside of my data classes but came up against a few roadblocks!

SetValue and GetValue methods accept an instance of class as input not Type of that class. As you want to set/get values of the properties of the class you are in, you can pass this to these methods.

public Deposits(List<Dictionary<string, string>> LPQReq)
{
    PropertyInfo[] properties = typeof(Deposits).GetProperties();

    foreach (Dictionary<string, string> PQList in LPQReq)
    {
        foreach (KeyValuePair<string, string> kvp in PQList)
        {
            if(properties.Any(x=>x.Name == kvp.Key) && 
               properties[kvp.Key].PropertyType == typeof(string))
            {
                properties[kvp.Key].SetValue(this, kvp.Value);
                //                            ^ here we pass current instance
            }
        }
    }
    foreach (PropertyInfo property in properties)
    {
        Console.WriteLine("Name: " + property.Name + ", Value: " + 
                property.GetValue(this));
        //                         ^ here we pass current instance
    }
}

What I'm not understanding from your code is, why you have a list of dictionary of name-values? you just need a dictionary of key-values for each object. I guess you want to initiate multiple instances of the same class, if so you must loop over the list and through the loop initiate the class with the dictionary. Something like this:

Constructor:

public Deposits(Dictionary<string, string> PQList)
{
    PropertyInfo[] properties = typeof(Deposits).GetProperties();
    foreach (KeyValuePair<string, string> kvp in PQList)
    {
         if(properties.Any(x=>x.Name == kvp.Key) && 
            properties[kvp.Key].PropertyType == typeof(string))
         {
             properties[kvp.Key].SetValue(this, kvp.Value);
         }
    }
    foreach (PropertyInfo property in properties)
    {
        Console.WriteLine("Name: " + property.Name + ", Value: " + 
                property.GetValue(this));
    }
}

Somewhere else:

List<Diposits> list = new List<Diposits>()
foreach (Dictionary<string, string> PQList in LPQReq)
{
   list.Add(new Diposits(PQList));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM