从具有指定属性的泛型类列表生成HTML表

bir*_*dus 10 c# generics reflection

我想从几个指定的参数生成一个HTML表.具体来说,我想传递给我的方法的两个参数是:IEnumerable列表,以及T的一些属性子集.例如,假设我有一个这个类的List:

class Person
{
  string FirstName
  string MiddleName
  string LastName
}
Run Code Online (Sandbox Code Playgroud)

假设该列表中有5个人.我想通过这样的方式获得该类(或任何其他任意类)的HTML表:

List<Person> people;
...add people to list

string HTML = GetMyTable(people, "FirstName", "LastName");
Run Code Online (Sandbox Code Playgroud)

我确定有一种更好的方法可以指定我希望从中生成表的属性(或者我希望从表中排除哪些属性,这样会更好,因为我通常会想要大多数或所有类的属性),但是我我不确定如何(我从未使用过反射,但我猜这是怎么回事).此外,该方法应接受任何类型的类的列表.

有关如何实现这一目标的任何聪明的想法?

L.B*_*L.B 22

也许是这样的?

var html = GetMyTable(people, x => x.LastName, x => x.FirstName);

public static string GetMyTable<T>(IEnumerable<T> list,params Func<T,object>[] fxns)
{

    StringBuilder sb = new StringBuilder();
    sb.Append("<TABLE>\n");
    foreach (var item in list)
    {
        sb.Append("<TR>\n");
        foreach(var fxn in fxns)
        {
            sb.Append("<TD>");
            sb.Append(fxn(item));
            sb.Append("</TD>");
        }
        sb.Append("</TR>\n");
    }
    sb.Append("</TABLE>");

    return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)

- 版本2.0--

public static string GetMyTable<T>(IEnumerable<T> list, params  Expression<Func<T, object>>[] fxns)
{

    StringBuilder sb = new StringBuilder();
    sb.Append("<TABLE>\n");

    sb.Append("<TR>\n");
    foreach (var fxn in fxns)
    {
        sb.Append("<TD>");
        sb.Append(GetName(fxn));
        sb.Append("</TD>");
    }
    sb.Append("</TR> <!-- HEADER -->\n");


    foreach (var item in list)
    {
        sb.Append("<TR>\n");
        foreach (var fxn in fxns)
        {
            sb.Append("<TD>");
            sb.Append(fxn.Compile()(item));
            sb.Append("</TD>");
        }
        sb.Append("</TR>\n");
    }
    sb.Append("</TABLE>");

    return sb.ToString();
}

static string GetName<T>(Expression<Func<T, object>> expr)
{
    var member = expr.Body as MemberExpression;
    if (member != null)
        return GetName2(member);

    var unary = expr.Body as UnaryExpression;
    if (unary != null)
        return GetName2((MemberExpression)unary.Operand);

    return "?+?";
}

static string GetName2(MemberExpression member)
{
    var fieldInfo = member.Member as FieldInfo;
    if (fieldInfo != null)
    {
        var d = fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute;
        if (d != null) return d.Description;
        return fieldInfo.Name;
    }

    var propertInfo = member.Member as PropertyInfo;
    if (propertInfo != null)
    {
        var d = propertInfo.GetCustomAttribute(typeof(DescriptionAttribute)) as DescriptionAttribute;
        if (d != null) return d.Description;
        return propertInfo.Name;
    }

    return "?-?";
}
Run Code Online (Sandbox Code Playgroud)

PS:fxn.Compile()反复调用可以在紧密循环中成为性能杀手.将它缓存在字典中会更好.

  • 太好了,LB 谢谢! (2认同)

小智 9

这就是我所做的,它似乎工作正常,而不是一个巨大的性能打击.

    public static string ToHtmlTable<T>(this List<T> listOfClassObjects)
    {
        var ret = string.Empty;

        return listOfClassObjects == null || !listOfClassObjects.Any()
            ? ret
            : "<table>" +
              listOfClassObjects.First().GetType().GetProperties().Select(p => p.Name).ToList().ToColumnHeaders() +
              listOfClassObjects.Aggregate(ret, (current, t) => current + t.ToHtmlTableRow()) +
              "</table>";
    }

    public static string ToColumnHeaders<T>(this List<T> listOfProperties)
    {
        var ret = string.Empty;

        return listOfProperties == null || !listOfProperties.Any()
            ? ret
            : "<tr>" +
              listOfProperties.Aggregate(ret,
                  (current, propValue) =>
                      current +
                      ("<th style='font-size: 11pt; font-weight: bold; border: 1pt solid black'>" +
                       (Convert.ToString(propValue).Length <= 100
                           ? Convert.ToString(propValue)
                           : Convert.ToString(propValue).Substring(0, 100)) + "..." + "</th>")) +
              "</tr>";
    }

    public static string ToHtmlTableRow<T>(this T classObject)
    {
        var ret = string.Empty;

        return classObject == null
            ? ret
            : "<tr>" +
              classObject.GetType()
                  .GetProperties()
                  .Aggregate(ret,
                      (current, prop) =>
                          current + ("<td style='font-size: 11pt; font-weight: normal; border: 1pt solid black'>" +
                                     (Convert.ToString(prop.GetValue(classObject, null)).Length <= 100
                                         ? Convert.ToString(prop.GetValue(classObject, null))
                                         : Convert.ToString(prop.GetValue(classObject, null)).Substring(0, 100) +
                                           "...") +
                                     "</td>")) + "</tr>";
    }
Run Code Online (Sandbox Code Playgroud)

要使用它,只需传递ToHtmlTable()一个List示例:

List documents = GetMyListOfDocuments(); var table = documents.ToHtmlTable();