You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现通用ViewModel在View Component中展示动态表格

无反射实现动态泛型表格视图模型方案求助

初始泛型设计

我原本想通过泛型结构实现一套可动态获取行对象属性的表格组件,定义如下:

public class Column<T> 
{
   // 列标题
   public string Name { get; set; }
   // 属性映射表达式
   public Expression<Func<T, string>> ValueMapper { get; set; }
}

public class Row<T>
{
   T Data { get; set; }
}

public class Table<T>
{
   IEnumerable<Row<T>> Rows { get; set; }
   IEnumerable<Column<T>> Columns { get; set; }
}

设计目标是把Table<T>作为View Component的ViewModel,实现任意类型数据的动态表格展示,不用为每种数据类型单独定义表格。

遇到的问题

我期望在Razor视图中用Table<IData>作为模型(约束T实现IData接口),代码如下:

@model Table<IData>

<table>
    <thead>
        <tr>
        @foreach(var col in Model.Columns) 
        {
            <td>@col.Name</td>
        }
        </tr>
    </thead>
    <tbody>
    @foreach(var row in Model.Rows)
    {
       <tr>
           @foreach(var col in Model.Columns)
           {
                <td>@col.ValueMapper.Compile().Invoke(row.Data)</td>
           }
       </tr>
    }
    </tbody>
</table>

但实际遇到了无法解决的类型转换问题:具体的Table<T>实例无法隐式转换为Table<IData>传递给视图。尝试用协变解决,但存在两个阻碍:

  • Row<T>的Data属性同时有getter和setter,属于不变类型,无法声明协变接口
  • Expression<Func<T, string>>中的T是输入参数,且该属性有getter和setter,协变无法生效

当前反射实现方案

无奈之下,我移除了泛型,改用object类型结合反射实现了功能,代码如下:

后端代码

public class Table
{
    public IEnumerable<Column> Columns {get; set;}
    public IEnumerable<Row> Rows {get; set;}
}  

public class Row
{
  public object Data {get; set;}
  public string GetValue(string propertyName) 
  {
    var toReturn = "";
    var pi = Data.GetType().GetProperty(propertyName);
    var value = pi.GetValue(Data);
    if(value == null) 
        return toReturn;

    if(value is DateTime dt)
        toReturn = dt.ToShortDateString();
    else
        toReturn = value.ToString();

     return toReturn;
  }
}

public class Column
{
   public string Name {get; set;}
   public string PropertyName {get; set;}
}

视图调用代码

@foreach(var row in Model.Rows)
{
   <tr>
       @foreach(var col in Model.Columns)
       {
            <td>@row.GetValue(col.PropertyName)</td>
       }
   </tr>
}

但反射会带来性能开销,我希望找到无需依赖反射的更优实现方案,恳请提供帮助。


内容的提问来源于stack exchange,提问作者Zach Painter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 02:24:38