.Net Core OfficeOpenXml создание excel файла из коллекции типизированной базовым классом

class Product
{
    public int Id {get:set;}
}

class Car : Product
{
   public string Name {get;set;}
}

var products = new List<Product>();
var car = new Car();
products.Add(car);

Потом из products создаю excel файл, но в нем нет поля Name. Избавится от восходящего преобразования проблематично. Можно ли с помощью OfficeOpenXml получить адекватный результат?


Такая же проблема с либой LinqToCsv . System.Xml.Serialization работает адекватно.


Пример кода для воспроизведения:

using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ConsoleApp1
{

    class Program
    {        
        static void Main(string[] args)
        {
            var products = new List<Product>();
            var car = new Car
            {
                Id = 1,
                Name = "лада"
            };
            products.Add(car);

            var plane = new Airplane
            {
                Id = 2,
                Speed = 500
            };
            products.Add(plane);

            var stream = Convert(products);
            var fstream = new FileStream("products.xlsx", FileMode.OpenOrCreate);
            stream.WriteTo(fstream);
            stream.Close();
            fstream.Close();
        }

        public static MemoryStream Convert(IEnumerable<Product> collection)
        {
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
            var result = new MemoryStream();
            using (var pck = new ExcelPackage())
            {
                AddSheet(pck, collection, "машины", typeof(Car));
                AddSheet(pck, collection, "самолеты", typeof(Airplane));

                pck.SaveAs(result);
            }


            return result;
        }

        private static void AddSheet(in ExcelPackage pck, IEnumerable<Product> collection, string sheetName, Type productType)
        {
            var products = collection.Where(p => p.GetType() == productType);
            if (products.FirstOrDefault() != null)
            {
                ExcelWorksheet tyreSheet = pck.Workbook.Worksheets.Add(sheetName);
                var tableRange = tyreSheet.Cells["A1"].LoadFromCollection(products, true);
                tableRange.AutoFilter = true;
                tableRange.AutoFitColumns();
            }
        }
    }

    class Product
    {
        public int Id { get; set; }
    }

    class Car : Product
    {
        public string Name { get; set; }
    }

    class Airplane : Product
    {
        public int Speed { get; set; }
    }
}

Ответы (1 шт):

Автор решения: aepot

Данный конкретный случай можно решить вот так:

static void Main(string[] args)
{
    var products = new List<Product>();
    var car = new Car
    {
        Id = 1,
        Name = "лада"
    };
    products.Add(car);

    var plane = new Airplane
    {
        Id = 2,
        Speed = 500
    };
    products.Add(plane);

    using (var ms = Convert(products))
    using (var fs = File.Create("products.xlsx"))
    {
        ms.WriteTo(fs);
    }
    Process.Start(new ProcessStartInfo { FileName = "products.xlsx", UseShellExecute = true });
}

public static MemoryStream Convert(IEnumerable<Product> collection)
{
    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
    var result = new MemoryStream();
    using (var pck = new ExcelPackage())
    {
        AddSheet(pck, collection.OfType<Car>(), "машины");
        AddSheet(pck, collection.OfType<Airplane>(), "самолеты");

        pck.SaveAs(result);
    }

    return result;
}

private static void AddSheet<T>(in ExcelPackage pck, IEnumerable<T> collection, string sheetName)
{
    if (collection.Any())
    {
        ExcelWorksheet tyreSheet = pck.Workbook.Worksheets.Add(sheetName);
        var tableRange = tyreSheet.Cells["A1"].LoadFromCollection(collection, true);
        tableRange.AutoFilter = true;
        tableRange.AutoFitColumns();
    }
}

То есть использовать непосредственно то обобщение, которое нужно.

→ Ссылка