Хочу сделать универсальный метод выгружающий таблицу в pdf.
Набросок метод:
static PdfPTable printTable<T>(IEnumerable<ColumnDefinition> columns, IEnumerable<T> rows, Font font)
{
var table = new PdfPTable(columns.Count());
foreach (var row in rows)
{
foreach (var column in columns)
{
var value = column.Property.GetValue(row, null);
System.Diagnostics.Debug.WriteLine(value as Enumerable);
if (value is IEnumerable<DTO.StateReason> nestedRows)
{
table.AddCell(new PdfPCell(printTable(nestedRows.GetColumnDefinitions(), nestedRows, font)) { Padding = 0});
}
else
{
var textContent = string.Empty;
if (value != null && !string.IsNullOrEmpty(column.Format))
{
switch (column.TypeName)
{
case nameof(DateTime):
{
textContent = ((DateTime)value).ToString(column.Format);
break;
}
case nameof(Int16):
case nameof(Int32):
case nameof(Int64):
{
textContent = ((int)value).ToString(column.Format);
break;
}
case nameof(Decimal):
{
textContent = ((decimal)value).ToString(column.Format);
break;
}
default:
break;
}
}
else if(value != null)
{
textContent = value.ToString();
}
table.AddCell(new PdfPCell(new Phrase(textContent, font)));
}
}
}
return table;
}
реализация метода GetColumnDefinition
static IEnumerable<ColumnDefinition> GetColumnDefinitions<T>(this IEnumerable<T> source)
{
try
{
var index = 0;
var result = (from property in typeof(T).GetProperties().OrderBy(x => x.Name)
let columnAttribute = property.GetCustomAttributes(typeof(ColumnAttribute), true).SingleOrDefault() as ColumnAttribute
let formatAttribute = property.GetCustomAttributes(typeof(DisplayFormatAttribute), true).SingleOrDefault() as DisplayFormatAttribute
let ignoreAttribute = property.GetCustomAttributes(typeof(IgnoreAttribute), true).SingleOrDefault() as IgnoreAttribute
where ignoreAttribute == null
select new ColumnDefinition
{
Property = property,
Name = columnAttribute?.Name ?? property.Name,
TypeName = columnAttribute?.TypeName ?? string.Empty,
Format = formatAttribute?.DataFormatString ?? string.Empty,
Order = columnAttribute?.Order ?? index++
})
.OrderBy(x => x.Order);
return result;
}
catch (Exception e)
{
throw;
}
}
пример классов для печати таблицы в pdf
public class ActHistoryList
{
[Services.Exports.Ignore]
public int Id { get; set; }
[Services.Exports.Ignore]
public int StateId { get; set; }
[Column("Состояние", Order = 0)]
public string State { get; set; }
[Column(Order = 1)]
public IList<StateReason> Reasons { get; set; } = new List<StateReason>();
[Column("Дата/Время", Order = 2, TypeName = nameof(DateTime)), DisplayFormat(DataFormatString = "dd.MM.yyyy HH:mm")]
public DateTime Timestamp { get; set; }
[Column("Автор", Order = 3)]
public string Author { get; set; }
}
public class StateReason
{
[Services.Exports.Ignore]
public int Id { get; set; }
[Column("Основание", Order = 1)]
public string Name { get; set; }
[Column("Комментарий", Order = 2)]
public string Description { get; set; }
}
Код рабочий, не соображу как реализовать рекурсивный вызов если значение value является массивом, коллекций и т.п., В коде это if(value is IEnumerable<DTO.StateReason> nestedRows), вместо DTO.StateReason может быть любой класс.
Если проблема заключается в том, что вместо DTO.StateReason может быть любой класс, то IEnumerable<DTO.StateReason> ты можешь заменить на IEnumerable и получить старый .NET 2.0 вариант с object'ами.
Если же интересует ответ на вопрос, то для того чтобы свойство было итерируемым, его тип должен реализовывать метод IEnumerator GetEnumerator();.
Соответственно, при помощи отражения (Reflection) ты можешь получить тип объекта (GetType), и перечислить его методы (GetMethods) в поисках нужного. Или же проверить, что он реализует интерфейс IEnumerable: typeof(IEnumerable).IsAssignableFrom(prop.PropertyType).
Так или иначе, попытки строить обобщённый код над Generic-ами - это всегда боль. По хорошему, стоит компилировать при помощи Expression или ILGenerator лямбда-выражение и вызывать его, чтобы нивелировать издержки привносимые отражением.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости