跳至页脚内容
使用 IRONXL

如何使用 C# Interop 与 IronXL.Excel 在 Excel 中创建透视表

在 Excel 中以编程方式生成数据透视表需要使用 C# Interop 及其 Office 依赖项,或者使用像IronXL这样可以独立工作的现代库。 本教程演示了这两种方法,强调了为什么开发人员越来越倾向于选择IronXL而不是传统的Interop方法。

本文将介绍如何编辑、创建、设计和计算数据透视表和数据透视组,以及如何进行自动分析和错误处理。

什么是Excel数据透视表?

数据透视表是Excel中最强大的工具之一。 它是一种简单易用的方法来总结大型数据集。 因此,数据透视表允许您轻松显示、理解和分析数值数据。 数据透视表不仅在 Excel 中可用,而且在其他程序中也可用,例如 Google Sheets、Apple Numbers 和 CSV 导出。 它提供了一种查看数据概览的解决方案——充当数据控制台,让人们能够以有意义的方式查看他们的信息——并与现实联系起来。

让我们先用错误的方法创建一个数据透视表,然后再学习如何用 C# 正确地创建它:

如何使用 C# Interop 在 Excel 表格中创建数据透视表?

C# Excel Interop 通过 COM 自动化提供对 Excel 数据透视表功能的直接访问。 这是许多开发人员在寻找工具以在C#中生成数据透视表时发现的传统方法:(不推荐)

如何在 .NET 中以传统方式创建数据透视表

using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();

// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;

// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing);

// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;
Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;
Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);

// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();

// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();

// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;

// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing);

// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;
Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;
Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);

// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();

// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

此 Interop 示例创建了一个原生 Excel 数据透视表,其中产品为行,地区为列,销售额汇总在数据区域中。 虽然功能正常,但这种方法需要安装Microsoft Office并仔细管理COM对象。 请参阅微软文档,了解为什么不应在现代开发中使用此方法。

C# 互操作会带来哪些问题?

Interop方法面临几个重大挑战:

遗憾的是,Stack Overflow 和其他编程网站仍然推荐它,因为它们的讨论主题仍然停留在 2000 年代初期的想法上。

部署依赖项:需要在运行源代码的每台机器上安装 Microsoft Office,包括生产服务器。 这增加了许可成本和部署复杂性。

内存管理:必须使用Marshal.ReleaseComObject()显式释放 COM 对象。 即使遗漏一个对象也会导致Excel进程挂在内存中,如Stack Overflow上详细记录

平台限制详情:这种老式的解决方案仅适用于安装了 Office 的 Windows 系统,速度可能非常慢,令用户感到困惑,并且可能导致内存泄漏。 不支持Linux、macOS、Docker容器或像Azure Functions这样的云平台。

性能问题:启动Excel应用程序实例速度慢且资源密集,尤其是用于服务器端处理时。

版本兼容性:不同的Office版本可能具有不同的COM接口,导致跨环境的兼容性问题。

IronXL 如何在不使用互操作的情况下以编程方式创建数据透视表?

IronXL采用不同的方法来创建数据透视表,使用托管代码,无需COM依赖。 虽然它不能创建 Excel 原生数据透视表,但它提供了强大的聚合功能。

如何以现代方式通过编程创建 XLSX 或 XLS 数据透视表

using IronXL;
using System.Linq;
using System.Data; // Keep this namespace
using static System.Data.DataTableExtensions; // Use 'using static' for DataTableExtensions

class Program
{
    static void Main(string[] args)
    {
        // Load Excel file - no Office required
        WorkBook workbook = WorkBook.Load("SalesData.xlsx");
        WorkSheet dataSheet = workbook.WorkSheets[0];
        // Convert to DataTable for powerful manipulation
        var dataTable = dataSheet.ToDataTable(true); // true = use first row as column headers
        // Create pivot-style aggregation using LINQ
        var pivotData = dataTable.AsEnumerable()
            .GroupBy(row => new {
                Product = row["Product"].ToString(),
                Region = row["Region"].ToString()
            }) //range
            .Select(g => new {
                Product = g.Key.Product,
                Region = g.Key.Region,
                TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
                AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
                Count = g.Count()
            });
        // Create pivot report worksheet
        WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
        // Build cross-tabulation structure
        var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p);
        var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r);
        // Create headers
        pivotSheet["A1"].Value = "Product/Region";
        int col = 2;
        foreach (var region in regions)
        {
            pivotSheet[$"{(char)('A' + col - 1)}1"].Value = region; // string
            col++;
        }
        // Populate pivot data
        int row = 2;
        foreach (var product in products)
        {
            pivotSheet[$"A{row}"].Value = product;
            col = 2;
            foreach (var region in regions)
            {
                var sales = pivotData
                    .Where(p => p.Product == product && p.Region == region)
                    .Select(p => p.TotalSales)
                    .FirstOrDefault();
                pivotSheet[$"{(char)('A' + col - 1)}{row}"].Value = sales;
                col++;
            }
            row++;
        }
        // Add totals using Excel formulas
        pivotSheet[$"A{row}"].Value = "Total"; // grand totals
        for (int c = 2; c <= regions.Count() + 1; c++)
        {
            pivotSheet[$"{(char)('A' + c - 1)}{row}"].Formula = $"=SUM({(char)('A' + c - 1)}2:{(char)('A' + c - 1)}{row - 1})";
        }
        // Proceeding to apply formatting
        var dataRange = pivotSheet[$"B2:{(char)('A' + regions.Count())}{row}"];
        dataRange.FormatString = "$#,##0.00";
        workbook.SaveAs("PivotReport.xlsx");
    }
}
using IronXL;
using System.Linq;
using System.Data; // Keep this namespace
using static System.Data.DataTableExtensions; // Use 'using static' for DataTableExtensions

class Program
{
    static void Main(string[] args)
    {
        // Load Excel file - no Office required
        WorkBook workbook = WorkBook.Load("SalesData.xlsx");
        WorkSheet dataSheet = workbook.WorkSheets[0];
        // Convert to DataTable for powerful manipulation
        var dataTable = dataSheet.ToDataTable(true); // true = use first row as column headers
        // Create pivot-style aggregation using LINQ
        var pivotData = dataTable.AsEnumerable()
            .GroupBy(row => new {
                Product = row["Product"].ToString(),
                Region = row["Region"].ToString()
            }) //range
            .Select(g => new {
                Product = g.Key.Product,
                Region = g.Key.Region,
                TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
                AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
                Count = g.Count()
            });
        // Create pivot report worksheet
        WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
        // Build cross-tabulation structure
        var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p);
        var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r);
        // Create headers
        pivotSheet["A1"].Value = "Product/Region";
        int col = 2;
        foreach (var region in regions)
        {
            pivotSheet[$"{(char)('A' + col - 1)}1"].Value = region; // string
            col++;
        }
        // Populate pivot data
        int row = 2;
        foreach (var product in products)
        {
            pivotSheet[$"A{row}"].Value = product;
            col = 2;
            foreach (var region in regions)
            {
                var sales = pivotData
                    .Where(p => p.Product == product && p.Region == region)
                    .Select(p => p.TotalSales)
                    .FirstOrDefault();
                pivotSheet[$"{(char)('A' + col - 1)}{row}"].Value = sales;
                col++;
            }
            row++;
        }
        // Add totals using Excel formulas
        pivotSheet[$"A{row}"].Value = "Total"; // grand totals
        for (int c = 2; c <= regions.Count() + 1; c++)
        {
            pivotSheet[$"{(char)('A' + c - 1)}{row}"].Formula = $"=SUM({(char)('A' + c - 1)}2:{(char)('A' + c - 1)}{row - 1})";
        }
        // Proceeding to apply formatting
        var dataRange = pivotSheet[$"B2:{(char)('A' + regions.Count())}{row}"];
        dataRange.FormatString = "$#,##0.00";
        workbook.SaveAs("PivotReport.xlsx");
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

因此,到2025年,这就是如何创建数据透视表。

输出

如何使用 C# Interop 与 IronXL 在 Excel 中创建数据透视表:图 1 - 原始 Excel 文件与我们创建的数据透视表,显示了单元格。

如何使用IronXL公式创建动态摘要?

对于需要动态更新(类似于创建数据透视表)的场景,IronXL 可以利用 Excel 的内置公式来计算数据透视表刷新功能,从而获得答案。 一般来说,这比之前的答案更好——您的记录将以更现代、更优雅的方式进行处理,使用的代码也更容易理解。 设置简单,无需联系客服或阅读手册。

// Load the workbook
WorkBook workbook = WorkBook.Load(inputPath);
// Rename the first worksheet so formulas reference correctly
WorkSheet dataSheet = workbook.WorkSheets[0];
dataSheet.Name = "DataSheet";
// Convert worksheet to DataTable
DataTable dataTable = dataSheet.ToDataTable(true);
// Create new summary worksheet
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region combinations
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region);
// Add header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with formulas
int rowIndex = 2;
foreach (var combo in uniqueCombos)
{
    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;
    // Adjust column references if your Sales column is C (not D)
    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    rowIndex++;
}
// Optional: add total row
summarySheet[$"A{rowIndex}"].Value = "Total";
summarySheet[$"C{rowIndex}"].Formula = $"=SUM(C2:C{rowIndex - 1})";
summarySheet[$"D{rowIndex}"].Formula = $"=SUM(D2:D{rowIndex - 1})";
// Save output file
workbook.SaveAs(outputPath);  //filename
// Load the workbook
WorkBook workbook = WorkBook.Load(inputPath);
// Rename the first worksheet so formulas reference correctly
WorkSheet dataSheet = workbook.WorkSheets[0];
dataSheet.Name = "DataSheet";
// Convert worksheet to DataTable
DataTable dataTable = dataSheet.ToDataTable(true);
// Create new summary worksheet
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region combinations
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region);
// Add header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with formulas
int rowIndex = 2;
foreach (var combo in uniqueCombos)
{
    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;
    // Adjust column references if your Sales column is C (not D)
    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    rowIndex++;
}
// Optional: add total row
summarySheet[$"A{rowIndex}"].Value = "Total";
summarySheet[$"C{rowIndex}"].Formula = $"=SUM(C2:C{rowIndex - 1})";
summarySheet[$"D{rowIndex}"].Formula = $"=SUM(D2:D{rowIndex - 1})";
// Save output file
workbook.SaveAs(outputPath);  //filename
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

这些公式与源数据保持实时连接,当数据表更改时自动更新 - 类似于数据透视表刷新行为,但没有Interop依赖。

如果我们将这段代码应用到上一个示例中的示例 Excel 文件(XLS / XLSX),页面上将显示以下字段:

如何在 Excel 中使用 C# Interop 与 IronXL 创建数据透视表:图 2 - 注意:C# 动态汇总输出在位置上下文中可见。

比较 C# Interop 和 IronXL 在数据透视表方面的性能

方面C# 互操作IronXL
办公室要求是的 - 完全安装否 - 独立库
平台支持仅限 Windows 系统Windows、Linux、macOS、Docker
内存管理需要手动清理 COM 对象自动 .NET 垃圾回收
部署复杂 - 办公许可简单 - 单个 DLL
表现Excel进程启动缓慢快速内存计算
云端兼容否 - Azure 限制是的 - 支持 Azure Functions
原生透视表无 - 聚合替代方案
发展速度速度慢 - COM 复杂性快速直观的 API

你应该选择哪种方法?

选择 C# 互操作的条件:

  • 必须使用原生 Excel 数据透视表对象
  • 仅在 Windows 系统上进行开发,且每台目标机器都已安装 Office 办公软件。
  • 仅部署到您管理的桌面系统
  • 现有遗留代码依赖于互操作性
  • 使用旧版 .NET Framework

选择 IronXL 的情况:

  • 部署到服务器或云环境和服务(Azure、AWS 等) 构建跨平台应用程序
  • 要求更高的性能和可靠性
  • 避免办公软件许可费用 需要更简洁、更易于维护的代码
  • 支持 Mac、iOS、Android 和/或 Linux 系统
  • 熟悉现代 .NET Framework Core 和 .NET 5、6、7、8、9、10。
  • 您需要在开发控制台/IDE 中拥有完全访问权限,以便根据数据范围以编程方式配置透视表中每个字段的设置。

结论

虽然C# Excel Interop可以开发本地数据透视表,但其部署限制和复杂性使其对于现代应用程序来说越来越不现实。 IronXL通过数据聚合和基于公式的汇总提供强大的替代方案,消除了对 Office 的依赖,同时保持了分析能力。 如果本文对您有帮助,请投票、评论或订阅。

对于正在寻找无需 Interop 即可开发透视表的替代方案的开发人员来说,IronXL 提供了一种更优的途径,避免了 COM 的复杂性,可在所有平台上运行,并简化了部署。 虽然没有本机数据透视对象的权衡通过更大的灵活性、更好的性能和消除Office许可要求得以补偿。

立即开始使用 IronXL。
green arrow pointer

准备好现代化您的Excel自动化并在现代C#中创建自己的数据透视表代码了吗?

通过 NuGet 包管理器,您可以在几秒钟内将 IronXL 集成到您的 C# 应用程序中。 免费试用购买 IronXL 许可证,以消除生产应用程序中的 Interop 依赖性。

常见问题解答

使用 IronXL 在 Excel 中创建数据透视表的优势是什么?

IronXL 可让您在 Excel 中创建数据透视表,而无需依赖 Office,与传统的 C# 互操作方法相比,它是一种更精简、更高效的解决方案。

IronXL 如何处理数据透视表的数据操作?

IronXL.Excel 提供强大的数据操作功能,能够创建透视风格的报表,而不会出现 Excel Interop 所带来的复杂问题。

IronXL 能否独立于 Excel Interop 使用?

是的,IronXL.Excel 可独立工作,允许开发人员生成数据透视表,而无需依赖 Excel Interop 及其相关依赖项。

与传统的 Excel 互操作方法相比,为什么开发人员更青睐 IronXL.Excel?

开发人员之所以偏爱 IronXL,是因为它省去了传统 Interop 方法所需的 Office 依赖关系,从而简化了创建数据透视表的过程。

使用 IronXL 需要安装 Microsoft Office 吗?

不,IronXL 不需要安装 Microsoft Office,因为它独立于 Office 运行,不像 C# Interop 需要依赖 Office。

IronXL 兼容现代 C# 编程吗?

是的,IronXL 的设计与现代 C# 编程无缝集成,提供了一种处理 Excel 数据操作任务的现代方法。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。