1

I have a Generic List of type List<InstanceDataLog> which has huge number of properties in it. I want to pass names of a few properties to a method and want to extract a refined List from within this list.

public void Export(string col)   //a,b,c
{
    string [] selectedcol = col.Split(',');
    var grid = new GridView();
    var data = TempData["InstanceDataList"];
    List<InstanceDataLog> lst = new List<InstanceDataLog>();
    List<EToolsViewer.APIModels.InstanceDataLog> lstrefined = new List<InstanceDataLog>();
    lst=   (List<EToolsViewer.APIModels.InstanceDataLog>)TempData["InstanceDataList"];

     var r= lst.Select(e => new {e.a, e.b}).ToList();// I would like to replace these hardcoded properties with names of properties present in `selectedcol `

    grid.DataSource =r;
    grid.DataBind();
}

To clear things up further, suppose InstanceDataLog has 5 properties : a,b,c,d,e I would like pass a,b and be able to extract a new list with only properties a,b

EDIT:

 $('#export').mousedown(function () {

 window.location = '@Url.Action("Export", "TrendsData",new { col = "a,b,c" })';

});
SamuraiJack
  • 5,131
  • 15
  • 89
  • 195
  • You could consider [Dynamic LINQ](https://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library). Alternatively, refer [this answer](http://stackoverflow.com/questions/16516971/linq-dynamic-select) –  Nov 29 '16 at 10:30
  • This is a complex problem i think. It is not only accesing the properties ny name, but also a variable number of properties. The second problem is a very difficult one, you may need something like [Dynamic Linq](https://dynamiclinq.codeplex.com) – Pikoh Nov 29 '16 at 10:30
  • You might consider manipulating the grid columns instead of the collection. – Crowcoder Nov 29 '16 at 10:31

2 Answers2

2

To keep compiler type/name checking suggest to pass a Func<InstanceDataLog, TResult> instead of array of names

public void Export<TResult>(Func<InstanceDataLog, TResult> selectProperties)   
{
        var grid = new GridView();
        var data = TempData["InstanceDataList"];

        var originalList = (List<InstanceDataLog>)TempData["InstanceDataList"];

        var filteredList = originalList.Select(selectProperties).ToList();

        grid.DataSource = filteredList;
        grid.DataBind();
}

Then use it:

Export(data => new { Id = data.Id, Name = data.Name });
Fabio
  • 31,528
  • 4
  • 33
  • 72
  • May we see an example call to that method? – Pikoh Nov 29 '16 at 10:34
  • How would I call this method in controller from View ? – SamuraiJack Nov 29 '16 at 10:57
  • Based on the question's update see @Maksim answer where he using `ExpandoObject` - I think that solution is very close to what you want – Fabio Nov 29 '16 at 11:03
  • Yeah his answer but i am not able to get it to work, I am getting An exception of type 'System.InvalidOperationException' occurred in System.Web.dll but was not handled in user code Additional information: The data source for GridView with id '' did not have any properties or attributes from which to generate columns. Ensure that your data source has content. – SamuraiJack Nov 29 '16 at 11:22
  • Instead of creating new "dynamic" DataSource, I think will be much easy just show/hide columns in `GridView` based on the provided names – Fabio Nov 29 '16 at 12:05
2

You could use such method to get properties:

private object getProperty(EToolsViewer.APIModels.InstanceDataLog e, string propName)
    {
 var propInfo =typeof(EToolsViewer.APIModels.InstanceDataLog).GetProperty(propName);
    return propInfo.GetValue(e);        
}

and with another function you could get all properties you want:

private dynamic getProperties(string[] props, EToolsViewer.APIModels.InstanceDataLog e )
{
    var ret = new ExpandoObject() as IDictionary<string, Object>;;
    foreach (var p in props)
    {
        ret.Add(p, getProperty(e, p));
    }       
    return ret;
}

The problem occurs if you try to assign DataSource with expando object. Solution is described hier:

Binding a GridView to a Dynamic or ExpandoObject object

We do need one more method:

public DataTable ToDataTable(IEnumerable<dynamic> items)
{
    var data = items.ToArray();
    if (data.Count() == 0) return null;

    var dt = new DataTable();
    foreach (var key in ((IDictionary<string, object>)data[0]).Keys)
    {
        dt.Columns.Add(key);
    }
    foreach (var d in data)
    {
        dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
    }
    return dt;
}

and use it:

var r = lst.Select(e => getProperties(selectedcol, e)).ToList();
grid.DataSource = ToDataTable(r);

The same thing, but ready to run for LinqPad:

void Main()
{
    var samples = new[] { new Sample { A = "A", B = "B", C = "C" }, new Sample { A = "A1", B = "B2", C = "C1" } };
    var r = samples.Select(e => getProperties(new[] {"A", "C", "B"}, e)).ToList();
    r.Dump();
}

private object getProperty(Sample e, string propName)
{
    var propInfo = typeof(Sample).GetProperty(propName);
    return propInfo.GetValue(e);
}

private dynamic getProperties(string[] props, Sample e)
{
    var ret = new ExpandoObject() as IDictionary<string, Object>; ;
    foreach (var p in props)
    {
        ret.Add(p, getProperty(e, p));
    }
    return ret;
}

public class Sample
{
    public string A { get; set;}
    public string B { get; set;}
    public string C { get; set;}
}

With output:

enter image description here

Community
  • 1
  • 1
Maksim Simkin
  • 9,561
  • 4
  • 36
  • 49
  • An exception of type `'System.InvalidOperationException' `occurred in `System.Web.dll` but was not handled in user code Additional information: The data source for GridView with id '' did not have any properties or attributes from which to generate columns. Ensure that your data source has content. – SamuraiJack Nov 29 '16 at 11:18
  • My proposed code doesn't call anything from system.web.dll. I've tried it out, not with your classes, i don't see them, but with my sample class and it works as wanted. – Maksim Simkin Nov 29 '16 at 12:06
  • @Arbaaz the problem is, that DataGrid doesn't understand dynamic. Hier is the solution for this problem : http://stackoverflow.com/questions/5573856/binding-a-gridview-to-a-dynamic-or-expandoobject-object – Maksim Simkin Nov 29 '16 at 12:30
  • That is just perfect! Thanks Maksim! – SamuraiJack Nov 29 '16 at 13:10