You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型Sheet类设计问题:如何在Book中存储多类型数据Sheet

嘿,我完全懂你现在卡在哪了——泛型处理不同类型集合的时候确实容易钻进死胡同,不过其实有个很直白的解决办法,咱们一步步捋:

核心思路:用非泛型基类/接口统一存储不同的Sheet

问题的根源在于Sheet<T>是泛型类,直接用List<Sheet<T>>只能存同一种T类型的工作表。咱们可以先定义一个非泛型的通用接口/抽象类,让所有Sheet<T>都实现它,这样Book里就能用这个非泛型类型的列表来容纳各种不同的工作表了。

步骤1:定义非泛型的ISheet接口

先把所有Sheet都需要的通用属性/方法抽出来,做成一个不带泛型的接口:

public interface ISheet
{
    // 工作表名称是所有Sheet都有的通用属性
    string SheetName { get; set; }
    // 通用方法:初始化Excel列的逻辑
    void PrepareExcelColumns();
}

步骤2:让泛型Sheet实现ISheet

现在你的Sheet<T>可以保留泛型特性,同时实现这个非泛型接口,这样它就具备了“通用Sheet”的身份:

public class Sheet<T> : ISheet
{
    public string SheetName { get; set; }
    // 依然保留泛型的Data列表,存储特定类型的数据
    public List<T> Data { get; set; } = new List<T>();

    public void PrepareExcelColumns()
    {
        // 这里可以根据T的属性生成Excel表头,比如用反射获取T的公共属性名
        var properties = typeof(T).GetProperties();
        // 后续生成Excel时的表头逻辑可以在这里完成
    }
}

步骤3:改造Book类,用List存储工作表

现在Book里的Sheets列表就可以换成List<ISheet>,这样不管是Sheet<Dog>还是Sheet<Planet>,都能轻松加进去:

public class Book
{
    public List<ISheet> Sheets { get; set; } = new List<ISheet>();

    // 便捷方法:直接添加泛型Sheet
    public void AddSheet<T>(Sheet<T> sheet)
    {
        Sheets.Add(sheet);
    }

    // 生成Excel的核心方法
    public void GenerateExcel(string outputPath)
    {
        foreach (var sheet in Sheets)
        {
            // 两种处理数据的方式可选:
            // 方式1:针对特定类型做定制化处理
            if (sheet is Sheet<Dog> dogSheet)
            {
                foreach (var dog in dogSheet.Data)
                {
                    // 写入dog.Name、dog.Age等字段到Excel
                }
            }
            else if (sheet is Sheet<Planet> planetSheet)
            {
                foreach (var planet in planetSheet.Data)
                {
                    // 写入planet.Name、planet.Diameter等字段到Excel
                }
            }

            // 方式2:用反射通用处理所有类型(更灵活,不用加一堆if-else)
            var sheetType = sheet.GetType();
            if (sheetType.IsGenericType && sheetType.GetGenericTypeDefinition() == typeof(Sheet<>))
            {
                // 获取Sheet<T>里的Data列表
                var dataProp = sheetType.GetProperty("Data");
                var dataList = dataProp?.GetValue(sheet) as IEnumerable;
                if (dataList == null) continue;

                // 获取T的类型和它的所有公共属性
                var itemType = sheetType.GetGenericArguments()[0];
                var properties = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                // 生成表头:遍历properties取属性名
                // 生成行数据:遍历dataList,逐个对象取属性值写入单元格
            }
        }
        // 最后执行保存Excel文件的逻辑
    }
}

用法示例

现在你从EF获取不同结果集后,就能轻松构建Book并生成Excel了:

// 从EF获取不同类型的数据
var dogs = await _dbContext.Dogs.ToListAsync();
var planets = await _dbContext.Planets.ToListAsync();

// 创建Book和对应的Sheet
var book = new Book();
book.AddSheet(new Sheet<Dog> { SheetName = "狗狗列表", Data = dogs });
book.AddSheet(new Sheet<Planet> { SheetName = "行星列表", Data = planets });

// 生成Excel文件
book.GenerateExcel(@"C:\output.xlsx");

这样既解决了Book容纳不同类型Sheet的问题,又保留了泛型的类型安全特性,后续扩展其他类型的Sheet(比如Sheet<Cat>)也完全没问题~

内容的提问来源于stack exchange,提问作者Atron Seige

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:45:20