我正在使用C#中的通用Excel导出器。我的观点是放置任何类型的集合,并指定应该使用lambda表达式导出类的哪些属性,我已经这样做了。我正在努力解决的问题是,当我的类中有复杂的属性时,导出的属性值是“Namespace.ClassName”(例如“MyApp.ViewModels.MyViewModel”)。
这是我的代码:
Excel导出器类:
public class ExcelExporter
{
public void ExportToExcel<T>(IEnumerable<T> data, params Expression<Func<T, object>>[] columns)
{
DataTable dataTable = this.ConvertToDataTable(data, columns);
//Export the dataTable object to Excel using some library...
}
private DataTable ConvertToDataTable<T>(IEnumerable<T> data, params Expression<Func<T, object>>[] columnsFunc)
{
DataTable table = new DataTable();
foreach (var column in columnsFunc)
{
string columnName = ReflectionUtility.GetPropertyDisplayName<T>(column);
table.Columns.Add(columnName);
}
foreach (T obj in data)
{
DataRow row = table.NewRow();
for (int i = 0; i < table.Columns.Count; i++)
{
row[table.Columns[i].ColumnName] = ReflectionUtility.GetPropertyValue<T>(obj, columnsFunc[i]);
}
table.Rows.Add(row);
}
return table;
}
ReflectionUtility类 - 提供获取属性名称和值的方法。 “GetPropertyDisplayName”方法从属性中读取[DisplayName]属性值并将其设置为Excel文档中的标题列(原因是我希望像'FirstName'这样的属性显示为'First Name'。
public static class ReflectionUtility
{
/// <summary>
/// Returns the display name of a property (set by using [DisplayName] attribute).
/// If [DisplayName] is not provided, returns the actual property name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public static string GetPropertyDisplayName<T>(Expression<Func<T, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
memberExpression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
}
var property = memberExpression.Member as PropertyInfo;
if (property != null)
{
var displayNameAttribute = property.GetCustomAttribute(typeof(DisplayNameAttribute), false) as DisplayNameAttribute;
if (displayNameAttribute != null)
{
return displayNameAttribute.DisplayName;
}
}
return memberExpression.Member.Name;
}
public static object GetPropertyValue<T>(T obj, Expression<Func<T, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
memberExpression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
}
var property = memberExpression.Member as PropertyInfo;
if (property != null)
{
// Note: If we want to export complex object, the object's value is something like "Namespace.ClassName", which is
// inappropriate for displaying. So we must specify additionally which property from the complex object should be visualized...
var value = property.GetValue(obj);
return value;
}
return null;
}
我如何使用ExcelExporter类:
ExcelExporter excelExporter = new ExcelExporter();
excelExporter.ExportToExcel<MyViewModel>(genericListToExport,
p => p.StringProperty1,
p => p.StringProperty2,
p => p.ComplexProperty.IntProperty1);
如何传递ComplexProperty.IntProperty1并获取它的值并处理ComplexProperty为null时的情况,因此我不会得到NullReferenceException。
以下是测试场景Excel输出:
感谢任何帮助!
答案 0 :(得分:4)
EPPlus可以将IEnumerable加载到工作表中。这意味着您可以加载Enumerable.Select
调用的结果,将列限制为只有您想要的列,例如:
var products=allProducts.Where(prod=>prod.CustomerId=14)
.Select(new {prod.Name,prod.Category});
sheet.Cells["A1"].LoadFromCollection(products);
如果需要,您可以使用它,或者您可以在ExcelRangeBase.LoadFromCollection中查看它是如何完成的。
查看代码,EPPlus查找DisplayName
和Description
属性以生成标题文本,然后再回到成员名称