13

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

class Person
{
  string FirstName
  string MiddleName
  string LastName
}

假设列表中有 5 个人。我希望能够通过执行以下操作来获取该类(或任何其他任意类)的 HTML 表:

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

string HTML = GetMyTable(people, "FirstName", "LastName");

我确信有更好的方法来指定我希望从哪些属性生成表(或者我想从表中排除哪些属性,这会更好,因为我通常需要大部分或所有类的属性),但我'不确定如何(我从未使用过反射,但我猜是这样)。此外,该方法应该接受任何类型的类的列表。

关于如何做到这一点的任何聪明的想法?

4

5 回答 5

33

也许是这样的?

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

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

PS:重复调用fxn.Compile()可能是紧密循环中的性能杀手。将其缓存在字典中会更好。

于 2012-06-20T19:07:51.490 回答
13

这就是我所做的,它似乎工作正常,并且没有对性能造成巨大影响。

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

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

列出文档 = GetMyListOfDocuments(); var table = 文档.ToHtmlTable();

于 2014-06-13T21:09:12.237 回答
4

这里有两种方法,一种使用反射:

public static string GetMyTable(IEnumerable list, params string[] columns)
{
    var sb = new StringBuilder();
    foreach (var item in list)
    {
        //todo this should actually make an HTML table, not just get the properties requested
        foreach (var column in columns)
            sb.Append(item.GetType().GetProperty(column).GetValue(item, null));
    }
    return sb.ToString();
}
//used like
string HTML = GetMyTable(people, "FirstName", "LastName");

或使用 lambda:

public static string GetMyTable<T>(IEnumerable<T> list, params Func<T, object>[] columns)
{
    var sb = new StringBuilder();
    foreach (var item in list)
    {
        //todo this should actually make an HTML table, not just get the properties requested
        foreach (var column in columns)
            sb.Append(column(item));
    }
    return sb.ToString();
}
//used like
string HTML = GetMyTable(people, x => x.FirstName, x => x.LastName);

使用 lambda,正在发生的事情是您将方法传递GetMyTable给获取每个属性的方法。这比反射有好处,比如强类型,可能还有性能。

于 2012-06-20T19:11:55.233 回答
4

祝你好运

扩展方法

  public static class EnumerableExtension
{
    public static string ToHtmlTable<T>(this IEnumerable<T> list, List<string> headerList, List<CustomTableStyle> customTableStyles, params Func<T, object>[] columns)
    {
        if (customTableStyles == null)
            customTableStyles = new List<CustomTableStyle>();

        var tableCss = string.Join(" ", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Table).Where(w => w.ClassNameList != null).SelectMany(s => s.ClassNameList)) ?? "";
        var trCss = string.Join(" ", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Tr).Where(w => w.ClassNameList != null).SelectMany(s => s.ClassNameList)) ?? "";
        var thCss = string.Join(" ", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Th).Where(w => w.ClassNameList != null).SelectMany(s => s.ClassNameList)) ?? "";
        var tdCss = string.Join(" ", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Td).Where(w => w.ClassNameList != null).SelectMany(s => s.ClassNameList)) ?? "";

        var tableInlineCss = string.Join(";", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Table).Where(w => w.InlineStyleValueList != null).SelectMany(s => s.InlineStyleValueList?.Select(x => String.Format("{0}:{1}", x.Key, x.Value)))) ?? "";
        var trInlineCss = string.Join(";", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Tr).Where(w => w.InlineStyleValueList != null).SelectMany(s => s.InlineStyleValueList?.Select(x => String.Format("{0}:{1}", x.Key, x.Value)))) ?? "";
        var thInlineCss = string.Join(";", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Th).Where(w => w.InlineStyleValueList != null).SelectMany(s => s.InlineStyleValueList?.Select(x => String.Format("{0}:{1}", x.Key, x.Value)))) ?? "";
        var tdInlineCss = string.Join(";", customTableStyles?.Where(w => w.CustomTableStylePosition == CustomTableStylePosition.Td).Where(w => w.InlineStyleValueList != null).SelectMany(s => s.InlineStyleValueList?.Select(x => String.Format("{0}:{1}", x.Key, x.Value)))) ?? "";

        var sb = new StringBuilder();

        sb.Append($"<table{(string.IsNullOrEmpty(tableCss) ? "" : $" class=\"{tableCss}\"")}{(string.IsNullOrEmpty(tableInlineCss) ? "" : $" style=\"{tableInlineCss}\"")}>");
        if (headerList != null)
        {
            sb.Append($"<tr{(string.IsNullOrEmpty(trCss) ? "" : $" class=\"{trCss}\"")}{(string.IsNullOrEmpty(trInlineCss) ? "" : $" style=\"{trInlineCss}\"")}>");
            foreach (var header in headerList)
            {
                sb.Append($"<th{(string.IsNullOrEmpty(thCss) ? "" : $" class=\"{thCss}\"")}{(string.IsNullOrEmpty(thInlineCss) ? "" : $" style=\"{thInlineCss}\"")}>{header}</th>");
            }
            sb.Append("</tr>");
        }
        foreach (var item in list)
        {
            sb.Append($"<tr{(string.IsNullOrEmpty(trCss) ? "" : $" class=\"{trCss}\"")}{(string.IsNullOrEmpty(trInlineCss) ? "" : $" style=\"{trInlineCss}\"")}>");
            foreach (var column in columns)
                sb.Append($"<td{(string.IsNullOrEmpty(tdCss) ? "" : $" class=\"{tdCss}\"")}{(string.IsNullOrEmpty(tdInlineCss) ? "" : $" style=\"{tdInlineCss}\"")}>{column(item)}</td>");
            sb.Append("</tr>");
        }

        sb.Append("</table>");

        return sb.ToString();
    }

    public class CustomTableStyle
    {
        public CustomTableStylePosition CustomTableStylePosition { get; set; }

        public List<string> ClassNameList { get; set; }
        public Dictionary<string, string> InlineStyleValueList { get; set; }
    }

    public enum CustomTableStylePosition
    {
        Table,
        Tr,
        Th,
        Td
    }
}

使用

 private static void Main(string[] args)
    {
        var dataList = new List<TestDataClass>
        {
            new TestDataClass {Name = "A", Lastname = "B", Other = "ABO"},
            new TestDataClass {Name = "C", Lastname = "D", Other = "CDO"},
            new TestDataClass {Name = "E", Lastname = "F", Other = "EFO"},
            new TestDataClass {Name = "G", Lastname = "H", Other = "GHO"}
        };

        var headerList = new List<string> { "Name", "Surname", "Merge" };

        var customTableStyle = new List<EnumerableExtension.CustomTableStyle>
        {
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Table, InlineStyleValueList = new Dictionary<string, string>{{"font-family", "Comic Sans MS" },{"font-size","15px"}}},
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Table, InlineStyleValueList = new Dictionary<string, string>{{"background-color", "yellow" }}},
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Tr, InlineStyleValueList =new Dictionary<string, string>{{"color","Blue"},{"font-size","10px"}}},
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Th,ClassNameList = new List<string>{"normal","underline"}},
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Th,InlineStyleValueList =new Dictionary<string, string>{{ "background-color", "gray"}}},
            new EnumerableExtension.CustomTableStyle{CustomTableStylePosition = EnumerableExtension.CustomTableStylePosition.Td, InlineStyleValueList  =new Dictionary<string, string>{{"color","Red"},{"font-size","15px"}}},
        };

        var htmlResult = dataList.ToHtmlTable(headerList, customTableStyle, x => x.Name, x => x.Lastname, x => $"{x.Name} {x.Lastname}");
    }

    private class TestDataClass
    {
        public string Name { get; set; }
        public string Lastname { get; set; }
        public string Other { get; set; }
    }

结果

<table class="normal underline" style="font-family:Comic Sans MS;font-size:15px;background-color:yellow">
<tr style="color:Blue;font-size:10px">
    <th style="background-color:gray">Name</th>
    <th style="background-color:gray">Surname</th>
    <th style="background-color:gray">Merge</th>
</tr>
<tr style="color:Blue;font-size:10px">
    <td style="color:Red;font-size:15px">A</td>
    <td style="color:Red;font-size:15px">B</td>
    <td style="color:Red;font-size:15px">A B</td>
</tr>
<tr style="color:Blue;font-size:10px">
    <td style="color:Red;font-size:15px">C</td>
    <td style="color:Red;font-size:15px">D</td>
    <td style="color:Red;font-size:15px">C D</td>
</tr>
<tr style="color:Blue;font-size:10px">
    <td style="color:Red;font-size:15px">E</td>
    <td style="color:Red;font-size:15px">F</td>
    <td style="color:Red;font-size:15px">E F</td>
</tr>
<tr style="color:Blue;font-size:10px">
    <td style="color:Red;font-size:15px">G</td>
    <td style="color:Red;font-size:15px">H</td>
    <td style="color:Red;font-size:15px">G H</td
</tr>

于 2018-10-12T13:06:46.733 回答
0

扩展@Tim 的答案

    public string GetHtmlTable<T, Tproperty>(IEnumerable<T> list, params Expression<Func<T, Tproperty>>[] columns)
    {
        var sb = new StringBuilder();


        sb.AppendLine("<table>");
        sb.AppendLine("<tr>");
        foreach (var column in columns)
        {
            sb.Append("<th>");
            sb.Append(GetPropertyName(Activator.CreateInstance<T>(), column));
            sb.Append("</th>");
        }
        sb.AppendLine("</tr>");
        sb.AppendLine("<tbody>");

        foreach (var item in list)
        {
            sb.AppendLine("<tr>");

            foreach (var column in columns)
            {
                var func = column.Compile();
                sb.Append("<td>");
                sb.Append(func(item));
                sb.Append("</td>");

            }
            sb.AppendLine("</tr>");
        }
        sb.AppendLine("</tbody>");
        sb.AppendLine("</table>");

        return sb.ToString();
    }






    public string GetPropertyName<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> propertyLambda)
    {
        Type type = typeof(TSource);


        var expressionBody = propertyLambda.Body;
        if (expressionBody is UnaryExpression expression && expression.NodeType == ExpressionType.Convert)
        {
            expressionBody = expression.Operand;
        }


        MemberExpression member = (MemberExpression)expressionBody;
        if (member == null)
            return "";

        PropertyInfo propInfo = member.Member as PropertyInfo;
        if (propInfo == null)
            return "";

        if (type != propInfo.ReflectedType &&
            !type.IsSubclassOf(propInfo.ReflectedType)) return "";

        return propInfo.Name;
    }
}
于 2020-06-19T16:27:44.157 回答