tags:

views:

821

answers:

3

How can I access dynamically properties from a generated LINQ class ?

Cause I would like to be able to customize the displayed table columns where Partner is the LINQ Class generated from a SQL Server Database Table.

<table class="grid">
  <thead>
   <tr>
     <% foreach (Column c in (IEnumerable)ViewData["columns"]) { %>
     <th><%= c.Title %></th>    
     <% } %>                               
   </tr>
 </thead>
 <tbody>
 <% foreach (Partner p in (IEnumerable)ViewData.Model) { %>
   <tr>
     <% foreach (Column c in (IEnumerable)ViewData["columns"]) { %>
?????   <th> <%= p.GetProperty(c.Name) %>  </th>  ?????
     <% } %>         
   </tr>       
 <% } %>
  </tbody>
</table>

Any idea how the code of the "p.GetProperty(c.Name)" method could look like ?

Forgive me if the Question is very simple but as I'm new to C# and LINQ I really couldnt figure it out.

+1  A: 

I believe the following will accomplish what you want:

p.GetType().GetProperty(c.Name).GetValue(p)
Sander
Thanks! Easy working solution without lots of coding effort !But performance wise I went for Marc's Solution not to determinethe property references again for each line.
Oliver
+2  A: 

Reflection should provide what you want - in particular,

typeof(Partner).GetProperty(c.Name).GetValue(p, null)

However, you might want to do this before the loop:

var columns = (IEnumerable<string>)ViewData["columns"];
var cols = columns.Select(colName =>
      typeof(Partner).GetProperty(colName)).ToList();

This gives you a set of re-usable PropertyInfo instances that you can use per row:

 foreach (var col in cols) { %>
     <th><%= col.GetValue(p,null) %></th>
 <% }

(should that <th/> be a <td/>, by the way?)

That should be a bit more efficient than repeatedly finding each property. There are other ways of doing this too (faster again).

Marc Gravell
Cheers Marc, as Sander's Solution it works as you outlined in the 1stproposal but the I readlly prefer the 2nd more performance orientedone ;-) Thanks ! PS: of course the <th/> should be <td/> tags !
Oliver
+1  A: 

Reflection is a pretty good fit here, but really - everything is known at compile time. So it's possible to specify everything at design time.

public class DataItem
{
  string Title {get;set;}
  object Value {get;set;}
}

public interface IDataItems
{
  IEnumerable<DataItem> Items()
}


//suppose LINQ gives you this:
public partial class Customer
{
  public string Name {get;set;}
  public string Address {get;set;}
  public int Age {get;set;}
}

//then you add this in another file.
//if there's a lot of this, it can be code genned by design-time reflection
public partial class Customer : IDataItems
{
  public IEnumerable<DataItem> IDataItems.Items()
  {
    yield return new DataItem() {"Name", Name};
    yield return new DataItem() {"Address", Address};
    yield return new DataItem() {"Age", Age};
  }
}

//and the foreach loops look like this:
foreach(DataItem d in ViewData.OfType<IDataItems>().First().Items())
{
  d.Title;
}

foreach(IDataItems container in ViewData.OfType<IDataItems>())
{
    foreach(DataItem d in container.Items())
    {
       d.Value;
    }
}
David B
Because it was the most code intensive solution I tried it last, but as I was aiming for the best performance I will defintley stay with this solution ! Thanks !
Oliver