/// <summary> /// Generic extension method yielding objects of specified type from table. /// </summary> /// <remarks> /// Exceptions are not catched. It works on all or nothing basis. /// Only primitives and enums are supported as property. /// Currently supports only tables with header. /// </remarks> /// <typeparam name="T">Type to map to. Type should be a class and should have parameterless constructor.</typeparam> /// <param name="table">Table object to fetch</param> /// <param name="onCaught"></param> /// <param name="configurationAction"></param> /// <returns>An enumerable of the generating type</returns> public static IEnumerable <T> AsEnumerable <T>(this ExcelTable table, OnCaught <T> onCaught = null, Action <IExcelConfiguration <T> > configurationAction = null) where T : class, new() { IExcelConfiguration <T> configuration = DefaultExcelConfiguration <T> .Instance; configurationAction?.Invoke(configuration); List <KeyValuePair <int, PropertyInfo> > mapping = PrepareMappings <T>(table); ExcelAddress bounds = table.GetDataBounds(); // Parse table for (int row = bounds.Start.Row; row <= bounds.End.Row; row++) { var item = (T)Activator.CreateInstance(typeof(T)); foreach (KeyValuePair <int, PropertyInfo> map in mapping) { object cell = table.WorkSheet.Cells[row, map.Key + table.Address.Start.Column].Value; PropertyInfo property = map.Value; try { TrySetProperty(item, property, cell); } catch (Exception ex) { if (!configuration.SkipCastingErrors) { var exceptionArgs = new ExcelTableExceptionArgs { ColumnName = table.Columns[map.Key].Name, ExpectedType = property.PropertyType, PropertyName = property.Name, CellValue = cell, CellAddress = new ExcelCellAddress(row, map.Key + table.Address.Start.Column) }; throw new ExcelTableConvertException($"The expected type of '{exceptionArgs.PropertyName}' property is '{exceptionArgs.ExpectedType.Name}', but the cell [{exceptionArgs.CellAddress.Address}] contains an invalid value.", ex, exceptionArgs ); } } } onCaught?.Invoke(item, row); // TODO: if (!configuration.SkipValidationErrors) { // Validate parsed object according to data annotations item.Validate(row); } yield return(item); } }
/// <inheritdoc /> /// <summary> /// Custom constructor that takes message, inner exception and conversion arguments /// </summary> /// <param name="message">Exception message</param> /// <param name="inner">Actual conversion exception catched</param> /// <param name="args">Information related to the circumstances of the exception</param> public ExcelTableConvertException(string message, Exception inner, ExcelTableExceptionArgs args) : base(message, inner) { Args = args; }