C# Excel 插入到某个范围导致的 OutOfMemory 异常
C# Excel OutOfMemory exception caused by inserting to a range
我一直致力于一个相当复杂的 C# VSTO 项目,它在 Excel 中做了 很多 不同的事情。但是,我最近偶然发现了一个我不知道如何解决的问题。恐怕将整个项目放在这里会使我的问题过于复杂并使每个人感到困惑,所以这就是问题所在:
//this is a simplified version of Range declaration which I am 100% confident in
Range range = worksheet.Range[firstCell, lastCell]
range.Formula = array;
//where array is a object[,] which basically contains only strings and also works perfeclty fine
应该将 [] 数组插入 Excel 范围的最后一行以前用于较小的 Excel 书籍,但现在对于 [=13] 的较大书籍会崩溃=] 并且我不知道为什么,因为它曾经使用一个维度只要 500 多个元素的数组,而现在它崩溃了一个少于 400 个元素的数组。此外,崩溃时 RAM 使用量约为 1.2GB,我知道这个项目能够 运行 完全没问题,RAM 使用量约为 3GB。
我尝试了以下操作:逐行插入此数组,然后逐个单元格插入它,在每次插入行或单元格之前调用 GC.Collect() 但它仍然会因System.OutOfMemoryException
。
因此,对于解决此问题或确定错误可能隐藏在哪里的任何帮助,我将不胜感激,因为我无法理解为什么它拒绝为长度较小的数组(但可能稍大一些)工作内容)在 1.2GB 的 RAM 使用级别,这大约是它过去处理的 1/3。谢谢!
编辑
我在评论中被告知上面的代码可能过于稀疏,所以这里有一个更详细的版本(我希望它不会太混乱):
List<object[][]> controlsList = new List<object[][]>();
// this list is filled with a quite long method calling a lot of other functions
// if other parts look fine, I guess I'll have to investigate it
int totalRows = 1;
foreach (var control in controlsList)
{
if (control.Length == 0)
continue;
var range = worksheet.GetRange(totalRows + 1, 1, totalRows += control.Length, 11);
//control is an object[n][11] so normally there are no index issues with inserting
range.Formula = control.To2dArray();
}
//GetRange and To2dArray are extension methods
public static Range GetRange(this Worksheet sheet, int firstRow, int firstColumn, int lastRow, int lastColumn)
{
var firstCell = sheet.GetRange(firstRow, firstColumn);
var lastCell = sheet.GetRange(lastRow, lastColumn);
return (Range)sheet.Range[firstCell, lastCell];
}
public static Range GetRange(this Worksheet sheet, int row, int col) => (Range)sheet.CheckIsPositive(row, col).Cells[row, col];
public static T CheckIsPositive<T>(this T returnedValue, params int[] vals)
{
if (vals.Any(x => x <= 0))
throw new ArgumentException("Values must be positive");
return returnedValue;
}
public static T[,] To2dArray<T>(this T[][] source)
{
if (source == null)
throw new ArgumentNullException();
int l1 = source.Length;
int l2 = source[0].Length(1);
T[,] result = new T[l1, l2];
for (int i = 0; i < l1; ++i)
for (int j = 0; j < l2; ++j)
result[i, j] = source[i][j];
return result;
}
我不是 100% 确定我的计算是否正确,但问题似乎出在 Interop 中。Excel/Excel 限制和我尝试插入的公式的长度:只要长度接近 8k字符,接近公式内容的 Excel 限制,System.OutOfMemoryException
弹出。当我选择不使用冗长的公式时,程序开始运行良好。
我一直致力于一个相当复杂的 C# VSTO 项目,它在 Excel 中做了 很多 不同的事情。但是,我最近偶然发现了一个我不知道如何解决的问题。恐怕将整个项目放在这里会使我的问题过于复杂并使每个人感到困惑,所以这就是问题所在:
//this is a simplified version of Range declaration which I am 100% confident in
Range range = worksheet.Range[firstCell, lastCell]
range.Formula = array;
//where array is a object[,] which basically contains only strings and also works perfeclty fine
应该将 [] 数组插入 Excel 范围的最后一行以前用于较小的 Excel 书籍,但现在对于 [=13] 的较大书籍会崩溃=] 并且我不知道为什么,因为它曾经使用一个维度只要 500 多个元素的数组,而现在它崩溃了一个少于 400 个元素的数组。此外,崩溃时 RAM 使用量约为 1.2GB,我知道这个项目能够 运行 完全没问题,RAM 使用量约为 3GB。
我尝试了以下操作:逐行插入此数组,然后逐个单元格插入它,在每次插入行或单元格之前调用 GC.Collect() 但它仍然会因System.OutOfMemoryException
。
因此,对于解决此问题或确定错误可能隐藏在哪里的任何帮助,我将不胜感激,因为我无法理解为什么它拒绝为长度较小的数组(但可能稍大一些)工作内容)在 1.2GB 的 RAM 使用级别,这大约是它过去处理的 1/3。谢谢!
编辑
我在评论中被告知上面的代码可能过于稀疏,所以这里有一个更详细的版本(我希望它不会太混乱):
List<object[][]> controlsList = new List<object[][]>();
// this list is filled with a quite long method calling a lot of other functions
// if other parts look fine, I guess I'll have to investigate it
int totalRows = 1;
foreach (var control in controlsList)
{
if (control.Length == 0)
continue;
var range = worksheet.GetRange(totalRows + 1, 1, totalRows += control.Length, 11);
//control is an object[n][11] so normally there are no index issues with inserting
range.Formula = control.To2dArray();
}
//GetRange and To2dArray are extension methods
public static Range GetRange(this Worksheet sheet, int firstRow, int firstColumn, int lastRow, int lastColumn)
{
var firstCell = sheet.GetRange(firstRow, firstColumn);
var lastCell = sheet.GetRange(lastRow, lastColumn);
return (Range)sheet.Range[firstCell, lastCell];
}
public static Range GetRange(this Worksheet sheet, int row, int col) => (Range)sheet.CheckIsPositive(row, col).Cells[row, col];
public static T CheckIsPositive<T>(this T returnedValue, params int[] vals)
{
if (vals.Any(x => x <= 0))
throw new ArgumentException("Values must be positive");
return returnedValue;
}
public static T[,] To2dArray<T>(this T[][] source)
{
if (source == null)
throw new ArgumentNullException();
int l1 = source.Length;
int l2 = source[0].Length(1);
T[,] result = new T[l1, l2];
for (int i = 0; i < l1; ++i)
for (int j = 0; j < l2; ++j)
result[i, j] = source[i][j];
return result;
}
我不是 100% 确定我的计算是否正确,但问题似乎出在 Interop 中。Excel/Excel 限制和我尝试插入的公式的长度:只要长度接近 8k字符,接近公式内容的 Excel 限制,System.OutOfMemoryException
弹出。当我选择不使用冗长的公式时,程序开始运行良好。