【问题标题】:How to extract particular properties from generic list based on property name sent as string array?如何根据作为字符串数组发送的属性名称从通用列表中提取特定属性?
【发布时间】:2016-11-29 10:24:24
【问题描述】:

我有一个List<InstanceDataLog> 类型的通用列表,其中包含大量属性。我想将一些属性的名称传递给一个方法,并想从这个列表中提取一个精炼的列表。

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

为了进一步澄清,假设 InstanceDataLog 有 5 个属性:a、b、c、d、e 我想传递 a、b 并能够提取一个只有属性 a、b 的新列表

编辑:

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

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

});

【问题讨论】:

  • 你可以考虑Dynamic LINQ。或者,请参考this answer
  • 我认为这是一个复杂的问题。它不仅可以访问名称的属性,还可以访问可变数量的属性。第二个问题非常难,你可能需要Dynamic Linq
  • 您可以考虑操作网格列而不是集合。

标签: c# asp.net .net asp.net-mvc generics


【解决方案1】:

你可以使用这样的方法来获取属性:

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

使用另一个函数,您可以获得所需的所有属性:

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

如果您尝试使用 expando 对象分配 DataSource,则会出现问题。解决方案描述如下:

Binding a GridView to a Dynamic or ExpandoObject object

我们确实需要另外一种方法:

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

并使用它:

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

同样的事情,但准备好为 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;}
}

有输出:

【讨论】:

  • 'System.InvalidOperationException' 类型的异常在 System.Web.dll 中发生,但未在用户代码中处理附加信息:ID 为 '' 的 GridView 的数据源没有任何要生成的属性或属性列。确保您的数据源有内容。
  • 我提议的代码没有从 system.web.dll 调用任何东西。我已经试过了,不是你的课程,我看不到它们,而是我的示例课程,它可以按需要工作。
  • @Arbaaz 问题是,DataGrid 不理解动态。 Hier 是这个问题的解决方案:stackoverflow.com/questions/5573856/…
  • 这简直太完美了!谢谢马克西姆!
【解决方案2】:

为了保持编译器类型/名称检查,建议传递 Func&lt;InstanceDataLog, TResult&gt; 而不是名称数组

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

然后使用它:

Export(data => new { Id = data.Id, Name = data.Name });

【讨论】:

  • 我们可以看一个对该方法的调用示例吗?
  • 如何从 View 调用控制器中的这个方法?
  • 根据问题的更新,请参阅@Maksim 回答他使用ExpandoObject 的地方 - 我认为该解决方案非常接近您想要的
  • 是的,他的回答是,但我无法让它工作,我得到 System.Web.dll 中发生“System.InvalidOperationException”类型的异常,但未在用户代码中处理其他信息: id 为 '' 的 GridView 的数据源没有任何属性或属性可用于生成列。确保您的数据源有内容。
  • 我认为不是创建新的“动态”数据源,而是根据提供的名称显示/隐藏GridView 中的列会容易得多
猜你喜欢
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
相关资源
最近更新 更多