58

Is there a way in c# to loop over the properties of a class?

Basically I have a class that contains a large number of property's (it basically holds the results of a large database query). I need to output these results as a CSV file so need to append each value to a string.

The obvious way it to manually append each value to a string, but is there a way to effectively loop over the results object and add the value for each property in turn?

Loofer
  • 6,841
  • 9
  • 61
  • 102
Sergio
  • 9,761
  • 16
  • 60
  • 88

11 Answers11

64

Sure; you can do that in many ways; starting with reflection (note, this is slowish - OK for moderate amounts of data though):

var props = objectType.GetProperties();
foreach(object obj in data) {
    foreach(var prop in props) {
        object value = prop.GetValue(obj, null); // against prop.Name
    }
}

However; for larger volumes of data it would be worth making this more efficient; for example here I use the Expression API to pre-compile a delegate that looks writes each property - the advantage here is that no reflection is done on a per-row basis (this should be significantly faster for large volumes of data):

static void Main()
{        
    var data = new[] {
       new { Foo = 123, Bar = "abc" },
       new { Foo = 456, Bar = "def" },
       new { Foo = 789, Bar = "ghi" },
    };
    string s = Write(data);        
}
static Expression StringBuilderAppend(Expression instance, Expression arg)
{
    var method = typeof(StringBuilder).GetMethod("Append", new Type[] { arg.Type });
    return Expression.Call(instance, method, arg);
}
static string Write<T>(IEnumerable<T> data)
{
    var props = typeof(T).GetProperties();
    var sb = Expression.Parameter(typeof(StringBuilder));
    var obj = Expression.Parameter(typeof(T));
    Expression body = sb;
    foreach(var prop in props) {            
        body = StringBuilderAppend(body, Expression.Property(obj, prop));
        body = StringBuilderAppend(body, Expression.Constant("="));
        body = StringBuilderAppend(body, Expression.Constant(prop.Name));
        body = StringBuilderAppend(body, Expression.Constant("; "));
    }
    body = Expression.Call(body, "AppendLine", Type.EmptyTypes);
    var lambda = Expression.Lambda<Func<StringBuilder, T, StringBuilder>>(body, sb, obj);
    var func = lambda.Compile();

    var result = new StringBuilder();
    foreach (T row in data)
    {
        func(result, row);
    }
    return result.ToString();
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • thanks for the answer, but got a doubt reagarding accessing properties of another class, like: if i have `List` where Booking is a class, and `Cab`as another class and i reference it as a property in the Booking Class. how shud i parse thru the `foreach` to fetch the properties of the Cab class as well...Thanks – Sandeep Jan 17 '13 at 07:02
  • ryt now i can get each property of the `Booking` class, as `foreach(var porp in obj2Insert) { //using prop.GetValue() to return the result and store it. }` But, this traverses thru the whole properties of Booking Entity, which i dnt require..! This is where i'm struck...! – Sandeep Jan 17 '13 at 08:41
  • thank you for this creative solution :) Can you specifiy "moderate amounts of data"? Could you give a very rough estimation about how many properties in total it would take to make the non-reflection solution worth the effort? – buddybubble Jan 17 '13 at 10:26
  • @buddybubble it is also multipled by rows, not just properties. For "how many" - you'd have to profile, I'm afraid – Marc Gravell Jan 17 '13 at 10:50
  • @Marc, Thanks for the nice snippet of code for large amount of data. I am not much familiar with Expressions Can you please briefly explain how the second code works? – Tejas Patel Oct 18 '13 at 01:33
  • @Tejas the Expression api is basically an AST, with two uses. The primary use is to represent intent so that tools like ORMs can translate it into things like SQL, but: it also contains all the info required to compile to IL, and the code to do so. So: it creates an AST that represents what we want to do, then compiles it into IL and obtains a delegate to the compiled method. – Marc Gravell Oct 18 '13 at 01:45
22
foreach (PropertyInfo prop in typeof(MyType).GetProperties())
{
    Console.WriteLine(prop.Name);
}
Steven
  • 166,672
  • 24
  • 332
  • 435
6

I tried various recommendations on this page, I couldn't quite get any of them to work. I started with the top answer (you'll notice my variables are similarly named), and just worked through it on my own. This is what I got to work - hopefully it can help someone else.

var prop = emp.GetType().GetProperties();     //emp is my class
    foreach (var props in prop)
      {
        var variable = props.GetMethod;

        empHolder.Add(variable.Invoke(emp, null).ToString());  //empHolder = ArrayList
      }

***I should mention this will only work if you're using get;set; (public) properties.

Aaron
  • 61
  • 1
  • 2
3

You can make a list of the object's properties

IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();

And then use a foreach to navigate into the list..

foreach (var property in properties)
{
    // here's code...
}
woof
  • 83
  • 2
  • 8
bAN
  • 13,375
  • 16
  • 60
  • 93
1

Use something like

StringBuilder csv = String.Empty;
PropertyInfo[] ps this.GetType().GetProperties();
foreach (PropertyInfo p in ps)
{
    csv.Append(p.GetValue(this, null);
    csv.Append(",");
}
Ive
  • 457
  • 5
  • 19
1
var csv = string.Join(",",myObj
    .GetType()
    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .Select(p => p.GetValue(myObj, null).ToString())
    .ToArray());
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
0
string target = "RECEIPT_FOOTER_MESSAGE_LINE" + index + "Column";
PropertyInfo prop = xEdipV2Dataset.ReceiptDataInfo.GetType().GetProperty(target);
Type t = xEdipV2Dataset.ReceiptDataInfo.RECEIPT_FOOTER_MESSAGE_LINE10Column.GetType();
prop.SetValue(t, fline, null);

Attent for that: target object must be setable

Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35
0
string notes = "";

Type typModelCls = trans.GetType(); //trans is the object name
foreach (PropertyInfo prop in typModelCls.GetProperties())
{
    notes = notes + prop.Name + " : " + prop.GetValue(trans, null) + ",";
}
notes = notes.Substring(0, notes.Length - 1);

We can then write the notes string as a column to the log table or to a file. You have to use System.Reflection to use PropertyInfo

Nagaraj Raveendran
  • 1,150
  • 15
  • 23
0

this is how to loop over the properties in vb.net , its the same concept in c#, just translate the syntax:

 Dim properties() As PropertyInfo = Me.GetType.GetProperties(BindingFlags.Public Or BindingFlags.Instance)
            If properties IsNot Nothing AndAlso properties.Length > 0 Then
                properties = properties.Except(baseProperties)
                For Each p As PropertyInfo In properties
                    If p.Name <> "" Then
                        p.SetValue(Me, Date.Now, Nothing)  'user p.GetValue in your case
                    End If
                Next
            End If
Ali Tarhini
  • 5,278
  • 6
  • 41
  • 66
0

Looping over properties

Type t = typeof(MyClass);
foreach (var property in t.GetProperties())
{                
}
0

getting values of properties from simple class object....

class Person
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var person1 = new Person
        {
            Name = "John",
            Surname = "Doe",
            Age = 47
        };

        var props = typeof(Person).GetProperties();
        int counter = 0;

        while (counter != props.Count())
        {
            Console.WriteLine(props.ElementAt(counter).GetValue(person1, null));
            counter++;
        }
    }
}