168

I'm currently setting all of the values of my class object Record.

This is the code that I'm using to populate the record at the moment, property by property.

// Loop through each field in the result set
for (int i = 0; i <= resultItems.Length; i++)
{

    Record newRecord = new Record()
    {
            itemtype =   resultItems[i - (fieldCount - 0)],
            itemdesc =   resultItems[i - (fieldCount - 1)],
            prodcode =   resultItems[i - (fieldCount - 2)],
            proddesc =   resultItems[i - (fieldCount - 3)],
            curstat =    resultItems[i - (fieldCount -4)],
            totfree =    resultItems[i - (fieldCount -5)],
            totphys =    resultItems[i - (fieldCount -6)],
            pcolgroup =  resultItems[i - (fieldCount -7)],
            scolgroup =  resultItems[i - (fieldCount -8)],
            totpo =      resultItems[i - (fieldCount - 9)],
            totso =      resultItems[i - (fieldCount - 10)],
            quality =    resultItems[i - (fieldCount - 11)],
            statusdesc = resultItems[i - (fieldCount - 12)],
            groupcode =  resultItems[i - (fieldCount - 13)],
            qualitydes = resultItems[i - (fieldCount - 14)],
            pcoldesc =   resultItems[i - (fieldCount - 15)],
            scoldesc =   resultItems[i - (fieldCount - 16)],
            pgroupdesc = resultItems[i - (fieldCount - 17)],
    };
}

Can I iterate through each of the properties dynamically without hard coding all of the property names?

Something like so:

// Create new Record instance
Record newRecord = new Record();

for (int e = 0; e < propertyCount.Length - 1; e++)
{
    newRecord[fieldname] = resultItems[i - (fieldCount - e)];
}
Luke
  • 22,826
  • 31
  • 110
  • 193
  • 3
    Have you tried Reflection? http://stackoverflow.com/questions/997747/c-sharp-reflection-accessing-the-fields-of-a-struct – kol Nov 16 '11 at 12:45
  • 1
    pls take a look at this link http://stackoverflow.com/questions/721441/c-sharp-how-to-iterate-through-classes-fields-and-set-properties – Glory Raj Nov 16 '11 at 12:47
  • Could you explain where and how you would want to maintain the relationship between a property and the index in the resultItems array? – Emond Nov 16 '11 at 12:56

5 Answers5

319

You could possibly use Reflection to do this. As far as I understand it, you could enumerate the properties of your class and set the values. You would have to try this out and make sure you understand the order of the properties though. Refer to this MSDN Documentation for more information on this approach.

For a hint, you could possibly do something like:

Record record = new Record();

PropertyInfo[] properties = typeof(Record).GetProperties();
foreach (PropertyInfo property in properties)
{
    property.SetValue(record, value);
}

Where value is the value you're wanting to write in (so from your resultItems array).

Samuel Slade
  • 8,405
  • 6
  • 33
  • 55
  • 1
    What if i want to use *property.Getvalue(someOtherClassObjectHavingExacltySameProperties)* instead of a *value*? ( I tried this **property?.SetValue(objAppointment, property.GetValue(temp));** but it gives me, **{"Object does not match target type."}** ) – Asif Mehmood Jan 24 '17 at 11:16
  • @MalikAsif I'm not sure I fully understand, but it sounds like you are trying to load a property from a different type. If you post a question on SO with an example and link it here, I'll take a look for you. – Samuel Slade Jan 27 '17 at 09:39
  • 3
    This is an absolute life saver - thank you! I'm iterating through all class properties to check I have a value (before writing it to XML) – Cordell Apr 25 '18 at 16:06
  • @Cordell, how did you do that? I tried property.GetValue() but it asks for an object as parameter. – user7792598 Aug 16 '18 at 19:52
  • @user7792598 You need to pass in the object from which you want to get the property value. If you need further help, post another StackOverflow question – Samuel Slade Aug 18 '18 at 18:11
  • @Marvin The only instance you need is the `record` instance. You need an instance of the type in order to get/set the property values – Samuel Slade Jul 19 '19 at 19:31
  • @SamuelSlade very useful! I use it with ExpandoObject to dynamically get query results then I assign values to a strongly-typed class -- saves me lots of time from having to specify all the column names or ordinals, extra noise, etc. – Leo Gurdian Feb 27 '20 at 21:14
  • Hi @SamuelSlade can you help with this question, please? https://stackoverflow.com/questions/68179138/iterate-through-class-properties-c-sharp – Nirdha Jun 29 '21 at 19:52
20
// the index of each item in fieldNames must correspond to 
// the correct index in resultItems
var fieldnames = new []{"itemtype", "etc etc "};

for (int e = 0; e < fieldNames.Length - 1; e++)
{
    newRecord
       .GetType()
       .GetProperty(fieldNames[e])
       .SetValue(newRecord, resultItems[e]);
}
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 2
    This looks good, but I was hoping to do it dynamically, rather than hard coding the fieldnames in there. Is this possible? Thanks – Luke Nov 16 '11 at 12:50
  • Also it seems that the `GetProperty` property is not available for my class instance. :/ – Luke Nov 16 '11 at 12:51
  • nope, there need to be a mapping somewhere between the resultItem indexes and the property names. – jgauffin Nov 16 '11 at 12:52
  • 1
    @Coulton How do you expect to associate each property to an index dynamically? That's not possible. –  Nov 16 '11 at 12:53
  • you can try `nameof(Item.Field)` instead of `"itemtype"` to avoid the hard coding as of C# 6.0 – Patrick Michaelsen Sep 27 '17 at 21:38
3

I tried what Samuel Slade has suggested. Didn't work for me. The PropertyInfo list was coming as empty. So, I tried the following and it worked for me.

    Type type = typeof(Record);
    FieldInfo[] properties = type.GetFields();
    foreach (FieldInfo property in properties) {
       Debug.LogError(property.Name);
    }
AKA
  • 5,479
  • 4
  • 22
  • 36
3

Yes, you could make an indexer on your Record class that maps from the property name to the correct property. This would keep all the binding from property name to property in one place eg:

public class Record
{
    public string ItemType { get; set; }

    public string this[string propertyName]
    {
        set
        {
            switch (propertyName)
            {
                case "itemType":
                    ItemType = value;
                    break;
                    // etc
            }   
        }
    }
}

Alternatively, as others have mentioned, use reflection.

Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
2

Adding to Samuel Slade's response for anyone who chooses that approach (which is excellent). Take into consideration two things:

  1. GetProperties() only gives you a list of PUBLIC properties in your class. (any PRIVATE ones will not be included).
  2. You should be aware that every property you call SetValue() on should have a setter method to do so, or else an ArgumentException will be thrown (i.e.: "The property's set accessor is not found").

Having said that, special care with properties with no setter method like below:

public string Username { get; set; }
public bool HasCar
    {
        get
        {
            return this.Car != null;
        }
    }

Here the first property will be able to be set to the specified value but the second one not because it does not have a setter method. What I do to solve this is use GetSetMethod() over the properties to discriminate the ones with no setter methods like below:

var properties = this.GetType().GetProperties();
foreach(var prop in properties)
{
    if(prop.GetSetMethod() != null) {
        prop.SetValue(this, null);
    };
}

Hope this comment saves you some time!

Cheers