获取泛型,lambda中包含的列表类型

时间:2017-07-31 16:06:08

标签: c# generics reflection lambda asp.net-mvc-5

即使我知道这些库已经存在,我决定创建一个MVC5 HtmlHelper库来从模型生成表。重点是在C#中练习(实际学习)关于泛型和lambdas。

我希望我的库能够使用如下语法生成HTML表:

@Html.DisplayTable(model => model.ListTest).Render()

此时,上述代码完美无缺。但是当我试图添加方法exclude时,一切都出错了......这就是我对lambdas和delegate的理解有多差的地方。 (它实际上是我第一次编写委托作为参数的代码)

以下是我希望拨打电话的方式

@Html.DisplayTable(model => model.ListTest).Exclude(l => l.Col1).Render()

然后这是我提供给我的视图的模型

public class TestViewModel
{
    public List<RowViewModel> ListTest { get; set; }
}

其中RowViewModel定义如下

public class RowViewModel
{
    public string Col1 { get; set; } = "Col1Value";
    public string Col2 { get; set; } = "Col2Value";
    public string Col3 { get; set; } = "Col3Value";
}

我的助手

public static class TableHelpers
{
    public static HtmlTable<TValue> DisplayTable<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression) where TValue : IList
    {
        Func<TModel, TValue> deleg = expression.Compile();
        var result = deleg(helper.ViewData.Model);

        return new HtmlTable<TValue>(result);
    }
}

我的“图书馆逻辑”

 public class HtmlTable<TValue> where TValue : IList
{
    private TValue _inputModel;
    private readonly TableViewModel _outputViewModel = new TableViewModel();

    public HtmlTable(TValue model)
    {
        Init(model);
    }

    public HtmlTable<TValue> Init(TValue model)
    {
        if(model.Count == 0)
            throw new ArgumentException("The list must not be empty");

        _inputModel = model;

        UpdateViewModel();

        return this;
    }

    private void UpdateViewModel()
    {
        var subType = _inputModel.GetContainedType();

        var properties = subType.GetProperties();
        _outputViewModel.Header = properties.Select(p => p.Name).ToList();
        _outputViewModel.Rows = new List<List<string>>();
        foreach (var row in _inputModel)
        {
            var values = _outputViewModel.Header.Select(col => subType.GetProperty(col).GetValue(row, null).ToString()).ToList();
            _outputViewModel.Rows.Add(values);
        }
    }

    public HtmlTable<TValue> Exclude<TSubValue>(Expression<Func<TValue, TSubValue>> expression)
    {

        Func<TValue, TSubValue> deleg = expression.Compile();
        var result = deleg(_inputModel);

        return this;
    }
}

如果我要向我的助手指定行的模型,我有点想知道应该怎么做,例如

@Html.DisplayTable<RowViewModel>(model => model.ListTest).Exclude(l => l.Col1).Render()

但我真的希望能够确定列表中包含的类型以使lambda工作。

所有这一切都没有任何意义,但是从理论的角度来理解lambdas一段时间之后我决定最好停止阅读文章并尝试用它做点什么......

1 个答案:

答案 0 :(得分:0)

我找到了解决方案,而且非常简单。

我所要做的就是用TValue替换Expression<Func<TModel, TValue>> expression中的IEnumerable<TValue>并删除where TValue : IList

这允许我打电话

@Html.DisplayTable(model => model.ListTest)

无需明确指定任何泛型类型。