如何使用 IronXL 在 Excel 中使用 C# 建立資料透視表
在 Excel 中程式化生成樞紐分析表需要使用 C# 與其 Office 依賴的互操作或者像 IronXL 這樣的現代程式庫,該程式庫可以獨立運作 — 這份教程展示了這兩種方法,並說明為什麼現代方法是更好的選擇。
在伺服器端或跨平台 .NET 程式碼中生成類似樞紐分析的報表歷來是一件痛苦的事。 傳統的 COM 互操作方式將您綁定到具有完整 Office 安裝的 Windows 機器上,如果您錯過了任何單一有關 COM 清理的呼叫,會生成記憶體洩漏,而且一旦您嘗試部署到 Linux 或 Docker 容器就會毀滅。 寫 IronXL 和 LINQ 聚合邏輯的現代替代方法可在任何 .NET 執行的地方運行,不需要 Office 授權,並為您提供簡潔、可讀的程式碼。
本指南詳細說明了這兩種技術。 您將看到原始的互操作方法,準確理解其脆弱原因,然後使用 C# 中的 IronXL 構建相同的樞紐分析樣式摘要表。 您還將看到如何使用 Excel 公式進行動態、自動更新的摘要,這些摘要像實際的樞紐分析表刷新一樣運行。
什麼是Excel樞紐分析表?
樞紐分析表是電子表格軟體中最強大的分析工具之一。 它通過分組列、聚合值並將結果投射到交叉核對佈局中來總結大資料集 — 所有這些都不需要您手動編寫任何公式。 微軟的官方樞紐分析表文件 提供了該功能在 Excel 內的詳細概述。
樞紐分析表出現在 Microsoft Excel、Google 表單、Apple Numbers 以及大多數其他電子表格工具中。 核心概念總是相同的:您定義列字段,列字段和值字段,工具為您構建一個摘要矩陣。 當底層資料發生更改時,您刷新樞紐分析表,摘要會自動更新。
在 C# 伺服器端程式碼中,您有兩個廣泛的選擇:
- C# 互操作 —— 通過 COM 自動化運行的 Excel 過程,以建立一個真正的原生樞紐分析表物件,位於一個 XLSX 文件內
- 使用 LINQ 聚合的 IronXL —— 將工作簿讀入記憶體,使用受控的 .NET 程式碼計算相同的摘要,並將結果寫入新工作表
這兩個選擇都能產生有用的輸出。 但只有其中之一能在現代部署環境中可靠運行。
如何使用 C# 互操作生成樞紐分析表?
C# Excel 互操作通過 COM 自動化為您提供了直接使用 Excel 原生樞紐分析表功能的途徑。 您建立一個 Excel.Application 物件,打開一個工作簿,定義指向資料範圍的樞紐快取,然後配置行字段、列字段和資料字段。
如何設置互操作樞紐分析表程式碼
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);
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices
' Create Excel application instance
Dim xlApp As New Excel.Application()
Dim xlWorkbook As Excel.Workbook = xlApp.Workbooks.Open("C:\Data\SalesData.xlsx")
Dim xlSheet As Excel.Worksheet = CType(xlWorkbook.Sheets(1), Excel.Worksheet)
Dim xlPivotSheet As Excel.Worksheet = CType(xlWorkbook.Sheets.Add(), Excel.Worksheet)
' Define data range for pivot table
Dim dataRange As Excel.Range = xlSheet.UsedRange
' Create pivot cache and pivot table
Dim pivotCache As Excel.PivotCache = xlWorkbook.PivotCaches().Create(Excel.XlPivotTableSourceType.xlDatabase, dataRange, Type.Missing)
Dim pivotTable As Excel.PivotTable = pivotCache.CreatePivotTable(xlPivotSheet.Cells(3, 1), "SalesPivot", Type.Missing, Type.Missing)
' Configure pivot table fields
Dim productField As Excel.PivotField = CType(pivotTable.PivotFields("Product"), Excel.PivotField)
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField
productField.Position = 1
Dim regionField As Excel.PivotField = CType(pivotTable.PivotFields("Region"), Excel.PivotField)
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField
regionField.Position = 1
Dim salesField As Excel.PivotField = CType(pivotTable.PivotFields("Sales"), Excel.PivotField)
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)
此Interop範例建立了一個本地Excel樞紐分析表,將產品作為行,地區作為列,銷售額在資料區域中進行匯總。 雖然它確實在 XLSX 文件內生成了一個真正的樞紐分析表物件,但需要安裝 Microsoft Office 並要求仔細管理 COM 物件。 如果錯過了任何單一 Marshal.ReleaseComObject 呼叫,您會發現陳舊的 Excel 過程在任務管理器中不斷積累。
在編寫任何程式碼之前如何安裝 IronXL
在跳到 IronXL 方法之前,請通過 NuGet 程式包管理器安裝程式庫:
Install-Package IronXL.Excel
伺服器、容器或開發機器上不需要安裝 Office。IronXL 完全在受控的 .NET 記憶體中讀取和寫入 XLSX、XLS 和 CSV 文件。
C# 互操作會產生哪些問題?
互操作方式在實際部署中呈現了幾個重要的挑戰,而且這些挑戰會迅速合成。 Stack Overflow 和其他編程資源仍然建議使用互操作,因為許多執行緒是在 2000 年初寫的,並且自那時起已經被鎖定 —— 因此建議凍結在時間中。
部署依賴項 —— 每一台運行您的程式碼的計算機必須安裝一份授權的 Microsoft Office 副本,包括生產伺服器和 CI/CD 構建代理。 這增加了授權成本和部署複雜性,這些是使用現代替代品可以完全避免的。
記憶體管理負擔 —— 必須使用 Marshal.ReleaseComObject() 顯式釋放 COM 物件。 即便是遺漏一個物件也會導致 Excel 過程無限期地掛在記憶體中,在 Stack Overflow 上已有廣泛的文件記錄。 在長期運行的服務或 ASP.NET 網頁應用中,這成為一個關鍵的資源洩漏。
平台限制 —— 只有在安裝了 Office 的 Windows 上才能使用互操作。 您無法在 Linux、macOS、Docker 容器或像 Azure 雲函式或 AWS Lambda 這類無伺服器平台上運行。 這完全阻止了您使用現代雲原生架構的可能性。
性能瓶頸 —— 啟動 Excel 應用實例需要較多的資源和很慢。對於需要生成數十或數百份報告的伺服器端批次處理,這種啟動延遲成為了一個嚴重的吞吐約束。
版本相容性不穩定 —— 不同的 Office 版本公開略有不同的 COM 介面。 針對 Office 2019 運作的程式碼可能在 Office 2016 或 Microsoft 365 上表現不同,您無法在部署中固定版本。 微軟文件上的 Office 互操作程式集 強調了這些版本限制作為已知的限制。
CI/CD 不相容 —— 大多數持續整合環境未安裝 Office。 測試您的樞紐分析表生成程式碼需要模擬整個 COM 層或維護一個安裝了授權 Office 的專用 Windows 代理。
對於任何目標 .NET 6 或以上的新 .NET 應用 —— 包括 .NET 10 —— 這些限制使得互操作成為不實際的選擇。
IronXL 如何在不使用互操作的情況下建立樞紐分析表?
IronXL 從不同的角度接近樞紐分析表建立。 而不是通過 COM 控制外部 Excel 過程,IronXL 將您的工作簿讀入受控的 .NET 記憶體,給您對單元格值、公式和工作表結構的直接存取。 然後您使用標準 LINQ 查詢構建樞紐樣式聚合,並將結果寫回新工作表。
如何使用 IronXL 和 LINQ 構建交叉分表摘要
以下範例載入一個銷售資料工作簿,計算一個按地區交叉匯總,並將摘要寫入新工作表——所有這些都不需要任何 Office 依賴:
using IronXL;
using System.Linq;
using System.Data;
// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];
// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers
// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
.GroupBy(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.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 the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();
// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}
// Populate data rows
for (int r = 0; r < products.Count; r++)
{
pivotSheet[$"A{r + 2}"].Value = products[r];
for (int c = 0; c < regions.Count; c++)
{
var sales = pivotData
.Where(p => p.Product == products[r] && p.Region == regions[c])
.Select(p => p.TotalSales)
.FirstOrDefault();
pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
}
}
// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
char col = (char)('B' + c);
pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}
// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";
workbook.SaveAs("PivotReport.xlsx");
using IronXL;
using System.Linq;
using System.Data;
// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];
// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers
// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
.GroupBy(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.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 the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();
// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}
// Populate data rows
for (int r = 0; r < products.Count; r++)
{
pivotSheet[$"A{r + 2}"].Value = products[r];
for (int c = 0; c < regions.Count; c++)
{
var sales = pivotData
.Where(p => p.Product == products[r] && p.Region == regions[c])
.Select(p => p.TotalSales)
.FirstOrDefault();
pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
}
}
// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
char col = (char)('B' + c);
pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}
// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";
workbook.SaveAs("PivotReport.xlsx");
Imports IronXL
Imports System.Linq
Imports System.Data
' Load Excel file -- no Office installation required
Dim workbook As WorkBook = WorkBook.Load("SalesData.xlsx")
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
' Convert to DataTable for flexible LINQ manipulation
Dim dataTable As DataTable = dataSheet.ToDataTable(True) ' True = first row as column headers
' Build pivot-style aggregation using LINQ grouping
Dim pivotData = dataTable.AsEnumerable() _
.GroupBy(Function(row) New With {
Key .Product = row("Product").ToString(),
Key .Region = row("Region").ToString()
}) _
.Select(Function(g) New With {
Key .Product = g.Key.Product,
Key .Region = g.Key.Region,
Key .TotalSales = g.Sum(Function(row) Convert.ToDecimal(row("Sales"))),
Key .AverageSale = g.Average(Function(row) Convert.ToDecimal(row("Sales"))),
Key .Count = g.Count()
})
' Create the pivot report worksheet
Dim pivotSheet As WorkSheet = workbook.CreateWorkSheet("PivotReport")
' Get distinct row and column values
Dim products = pivotData.Select(Function(p) p.Product).Distinct().OrderBy(Function(p) p).ToList()
Dim regions = pivotData.Select(Function(p) p.Region).Distinct().OrderBy(Function(r) r).ToList()
' Write column headers
pivotSheet("A1").Value = "Product / Region"
For c As Integer = 0 To regions.Count - 1
pivotSheet($"{ChrW(AscW("B"c) + c)}1").Value = regions(c)
Next
' Populate data rows
For r As Integer = 0 To products.Count - 1
pivotSheet($"A{r + 2}").Value = products(r)
For c As Integer = 0 To regions.Count - 1
Dim sales = pivotData _
.Where(Function(p) p.Product = products(r) AndAlso p.Region = regions(c)) _
.Select(Function(p) p.TotalSales) _
.FirstOrDefault()
pivotSheet($"{ChrW(AscW("B"c) + c)}{r + 2}").Value = sales
Next
Next
' Add a totals row using Excel SUM formulas
Dim totalRow As Integer = products.Count + 2
pivotSheet($"A{totalRow}").Value = "Total"
For c As Integer = 0 To regions.Count - 1
Dim col As Char = ChrW(AscW("B"c) + c)
pivotSheet($"{col}{totalRow}").Formula = $"=SUM({col}2:{col}{totalRow - 1})"
Next
' Apply currency formatting to the data range
Dim dataRange = pivotSheet($"B2:{ChrW(AscW("B"c) + regions.Count - 1)}{totalRow}")
dataRange.FormatString = "$#,##0.00"
workbook.SaveAs("PivotReport.xlsx")
這產生了與原生 Excel 樞紐分析表相同的交叉匯總概要。 您擁有對每個單元格、公式和格式字串的完全程式化控制 —— 並且無需清理 COM 物件。

如何使用 Excel 公式建立動態摘要?
對於希望摘要表保持活躍的情境 —— 當源資料更改時自動重新計算 —— IronXL 讓您直接將 Excel 公式字串寫入單元格。 這為您提供了類似於樞紐分析表的自動刷新功能,無需任何互操作依賴。
這裡的關鍵功能是 SUMIFS 和 COUNTIFS。 SUMIFS 根據多個條件列條件對範圍進行合計; COUNTIFS 計算匹配的行。 兩者都接受命名工作表的引用,因此您可以按名稱直接將摘要表指向源資料表。
如何使用 IronXL 編寫基於公式的聚合
using IronXL;
using System.Data;
string inputPath = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";
WorkBook workbook = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];
// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";
// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
.Select(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.Distinct()
.OrderBy(x => x.Product)
.ThenBy(x => x.Region)
.ToList();
// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
int rowIndex = i + 2;
var combo = uniqueCombos[i];
summarySheet[$"A{rowIndex}"].Value = combo.Product;
summarySheet[$"B{rowIndex}"].Value = combo.Region;
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}\")";
}
// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";
workbook.SaveAs(outputPath);
using IronXL;
using System.Data;
string inputPath = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";
WorkBook workbook = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];
// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";
// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
.Select(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.Distinct()
.OrderBy(x => x.Product)
.ThenBy(x => x.Region)
.ToList();
// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
int rowIndex = i + 2;
var combo = uniqueCombos[i];
summarySheet[$"A{rowIndex}"].Value = combo.Product;
summarySheet[$"B{rowIndex}"].Value = combo.Region;
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}\")";
}
// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";
workbook.SaveAs(outputPath);
Imports IronXL
Imports System.Data
Imports System.Linq
Dim inputPath As String = "SalesData.xlsx"
Dim outputPath As String = "DynamicSummary.xlsx"
Dim workbook As WorkBook = WorkBook.Load(inputPath)
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
' Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet"
' Convert to DataTable to enumerate unique product/region combinations
Dim dataTable As DataTable = dataSheet.ToDataTable(True)
Dim summarySheet As WorkSheet = workbook.CreateWorkSheet("DynamicSummary")
' Get unique product-region pairs
Dim uniqueCombos = dataTable.AsEnumerable() _
.Select(Function(row) New With {
.Product = row("Product").ToString(),
.Region = row("Region").ToString()
}) _
.Distinct() _
.OrderBy(Function(x) x.Product) _
.ThenBy(Function(x) x.Region) _
.ToList()
' Header row
summarySheet("A1").Value = "Product"
summarySheet("B1").Value = "Region"
summarySheet("C1").Value = "Total Sales"
summarySheet("D1").Value = "Count"
' Populate rows with live SUMIFS / COUNTIFS formulas
For i As Integer = 0 To uniqueCombos.Count - 1
Dim rowIndex As Integer = i + 2
Dim combo = uniqueCombos(i)
summarySheet($"A{rowIndex}").Value = combo.Product
summarySheet($"B{rowIndex}").Value = combo.Region
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}"")"
Next
' Grand total row
Dim totalRow As Integer = uniqueCombos.Count + 2
summarySheet($"A{totalRow}").Value = "Total"
summarySheet($"C{totalRow}").Formula = $"=SUM(C2:C{totalRow - 1})"
summarySheet($"D{totalRow}").Formula = $"=SUM(D2:D{totalRow - 1})"
workbook.SaveAs(outputPath)
這些公式保持與源資料的即時連接。 當有人更新 DataSheet 中的值時,Excel 在下次打開或刷新時自動重新計算摘要 —— 為您提供了與原生樞紐分析表刷新周期相同的行為,無需 Com 自動化。
當您將此應用於先前範例中使用的相同銷售資料工作簿時,輸出看起來像這樣:

基於公式的方法也為您提供了新增條件格式化、資料棒或圖標集到摘要單元格的能力,使用 IronXL 的單元格格式化 API,使您的報告在無需在 Excel UI 中手動工作的情況下可視化清晰。
兩種方法如何比較?
在選擇一種方法之前,對比交互側的折衷選擇有助於做出決定。下表涵蓋了生產 .NET 開發中最重要的維度:
| 要素 | C# 互操作 | IronXL |
|---|---|---|
| 需要 Office | 是的 —— 每一台計算機上都需全面安裝 | 否 —— 獨立的 NuGet 程式包 |
| 平台支持 | 僅限Windows | Windows、Linux、macOS、Docker |
| 記憶體管理 | 需要手動COM清理 | 自動.NET垃圾回收 |
| 部署複雜性 | 高 —— Office 授權 + 安裝 | 低 —— 單個 DLL 引用 |
| 性能 | 慢 —— Excel 過程啟動開銷 | 快 —— 記憶體內計算 |
| 云相容 | 否 —— 在 Azure 函式、AWS Lambda 上被阻止 | 是的 —— 在任何雲平台上運行 |
| 原生樞紐分析表物件 | 是的 —— 完整的 Excel 樞紐分析表 | 否 —— 基於聚合的等效項 |
| 開發速度 | 慢 —— COM 複雜性 | 快 —— 流暢的受控 API |
| .NET 10 支持 | 有限 —— COM 綁定問題 | 全面 —— 針對現代 .NET |
唯一的情境是當您特別需要原生 Excel 樞紐分析表物件嵌入在 XLSX 文件中時,Interop 才有明顯優勢 —— 例如,如果下游使用者必須使用 Excel 的內建樞紐分析表 UI 與其互動(鑽取、篩選、交互式更改聚合功能)。 在其他所有情況下,IronXL 的方法更易書寫、更易部署、也更具可移植性。
您應該選擇哪種方法?
正確的選擇取決於您的部署環境和使用者需求。
僅當以下情況選擇 C# 互操作:
- 您的使用者需要可以在 Excel UI 中交互處理的原生 Excel 樞紐分析表物件
- 您的目標是封閉的 Windows 桌面環境,在那裡每台計算機上都保證安裝了 Office
- 您正在維護以互操作為依賴的舊版 .NET Framework 程式碼,而目前無法進行重寫
當以下情況選擇IronXL:
- 您正在部署到伺服器、容器或任何雲環境(Azure、AWS、GCP)
- 您需要對 Linux、macOS 或基於 Docker 的構建的跨平台支持
- 您希望避免 COM 生命周期管理的不整潔、可維護程式碼
- 您的目標是 .NET 5、6、7、8、9 或 10
- 您希望在伺服器基礎設施上避免微軟 Office 授權費
- 您需要快速批次處理大量工作簿,無需每文件 Excel 過程啟動
對於絕大多數現代 .NET 應用而言,IronXL 是實用的選擇。基於聚合的輸出滿足所有真實報告要求,並且您得到了完全的可移植性。
您可以進一步探索有關 IronXL 的功能 —— 包括單元格格式化、公式求值、資料驗證和圖表生成 —— 在 IronXL 文件 和 IronXL 範例庫 中。
今天怎麼開始使用 IronXL?
IronXL 程式庫在 NuGet 上可使用,新增到任何 .NET 專案不需一分鐘:
Install-Package IronXL.Excel
一旦安裝,您可以載入現有工作簿或建立新工作簿,讀取和寫入單元格值,應用公式,設置格式字串,並保存到 XLSX —— 所有這些都有一個簡潔、文件齊全的 API。 沒有 COM,沒有 Office 依賴,沒有特別的伺服器配置要求。
完整的 API 文件,請參見 IronXL 入門指南、C# Excel 互操作遷移指南 和 IronXL 程式碼範例。 您還可以在 IronXL 比較文章中比較 IronXL 與其他 Excel 程式庫。
一份免費試用授權讓您在提交前測試完整功能於您自己的專案中。 當您準備好部署到生產環境時,一份商業 IronXL 授權移除試用水印並包括優先支援。 從免費試用開始,看看跨平台 Excel 自動化能變得多麼簡單。
常見問題
如何使用C#在Excel中建立無Interop的樞紐分析表?
使用IronXL,您可以在Excel中使用C#建立無Interop的樞紐分析表,此工具提供強大的資料操作能力,獨立於Office依賴。
使用IronXL生成樞紐分析表有什麼優勢?
IronXL允許開發人員在不依賴Excel Interop的情況下生成樞紐分析表,消除了對Office安裝的需求,並降低了部署的複雜性。
IronXL是否與.NET應用程式相容?
是的,IronXL完全相容.NET應用程式,提供易於使用的API用於Excel操作,包括建立樞紐分析表。
IronXL是否需要在伺服器上安裝Excel?
不,IronXL不需要在伺服器上安裝Excel。它獨立運行,允許無縫整合到伺服器端應用程式中。
我可以使用IronXL在Excel中操作資料嗎?
是的,IronXL提供強大的資料操作功能,使開發人員能夠建立、修改和分析Excel資料,包括建立樞紐分析表。
為什麼開發人員可能更喜歡IronXL而不是傳統的Interop方法?
由於IronXL不依賴Office,部署更簡單,並且在Excel操作方面具有全面的功能,開發人員可能更喜歡它而非傳統Interop方法。
IronXL為Excel資料操作提供了什麼功能?
IronXL提供的功能包括讀取和寫入Excel檔案,建立和編輯試算表,以及生成樞紐分析表,全部無需Excel Interop。




