我想从几个指定的参数生成一个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");
我确信有更好的方法可以指定我希望从中生成表格的属性(或者我希望从表格中排除哪些属性,这样会更好,因为我通常需要大多数或所有类的属性) ,但我不确定(我从未使用过反射,但我猜这是怎么回事)。此外,该方法应接受任何类型的类的列表。
关于如何实现这一目标的任何聪明的想法?
答案 0 :(得分: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();
}
- 版本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()
可能会在紧密循环中成为性能杀手。将它缓存在字典中会更好。
答案 1 :(得分: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>";
}
要使用它,只需传递ToHtmlTable()一个List 例如:
列出文件= GetMyListOfDocuments(); var table = documents.ToHtmlTable();
答案 2 :(得分:3)
以下是两种方法,一种使用反射:
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");
或者使用lambdas:
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);
使用lambdas,正在发生的事情是你将方法传递给GetMyTable
方法来获取每个属性。这有利于反击,如强类型和可能的性能。
答案 3 :(得分:0)
祝你好运
扩展方式
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>
答案 4 :(得分: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;
}
}