Oliver
Oliver

Reputation: 301

dynamic property access for generated LINQ Classes

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 couldn't figure it out.

Upvotes: 3

Views: 2446

Answers (4)

King Friday
King Friday

Reputation: 26076

No. These are not the answers. I just found it!

This guy is using an example dynamic typing by casting anonymous types. No class definitions needed or special extension methods to Linq! This is so freakin cool.

http://kirillosenkov.blogspot.com/2008/01/how-to-create-generic-list-of-anonymous.html

This is one of those days that opens up some great possibilities for dynamic searching on anonymous types.

var anonymousTypeExample = new { startYear = 2000, endYear = 2000, model = "test" };
var list = (new[] { anonymousTypeExample }).ToList();

list.Clear();

list.Add(new{
    startYear = 1990,
    endYear = 2004,
    model = "Honda"
});
list.Add(new
{
    startYear = 1989,
    endYear = 1989,
    model = "KTM"
});
list.Add(new
{
    startYear = 1989,
    endYear = 1989,
    model = "KTM"
});

list = list.OrderBy(l => l.startYear).ToList();

foreach(var l in list)
{
    <div>@l.model @l.startYear - @l.endYear</div>
}

Upvotes: 0

Amy B
Amy B

Reputation: 110071

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;
    }
}

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062600

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).

Upvotes: 4

Sander
Sander

Reputation: 26354

I believe the following will accomplish what you want:

p.GetType().GetProperty(c.Name).GetValue(p)

Upvotes: 2

Related Questions