2

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!

Community
  • 1
  • 1
Our Man in Bananas
  • 5,809
  • 21
  • 91
  • 148
  • I would only go ahead with this if you have no considerations for performance. – Aron Aug 20 '15 at 18:09
  • @Aron: Yes, Reflection is considerably slower, but it means I can write one method to populate a dozen or more data classes (which will be the data sources for VS 2013 reports)... and anyway for this service, it's a case of maybe 2 dozen transactions per hour ... so performance measured in less than a second shouldn't hurt as currently we're printing the reports using MS Word, and that's seriously slow (7 seconds minimum per transaction) due to the Word Interop overhead. – Our Man in Bananas Aug 20 '15 at 18:14

1 Answers1

2

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));
}
Taher Rahgooy
  • 6,528
  • 3
  • 19
  • 30
  • @TRahgooy: Thanks, the dictionary is a list of key-value pairs, with the name of the member of the data class, and the corresponding value taken from a tab-delimited string which I take off the iSeries Message Queue.. – Our Man in Bananas Aug 21 '15 at 08:59
  • You should cache your reflection-based properties initialization code `PropertyInfo[] properties = typeof(Deposits).GetProperties();` by extracting that into a `static` field - that way you'll do that only once during the lifetime of the application. – Oliver May 08 '23 at 10:42