Я приму это как вызов и сделаю ставку, что самый быстрый способ переместить ваши данные между Excel и C # - это использовать Excel-Dna - http://exceldna.codeplex.com . (Отказ от ответственности: я разрабатываю Excel-Dna. Но это все еще верно ...)
Поскольку он использует собственный интерфейс .xll, он пропускает все накладные расходы на интеграцию COM, которые вы имели бы с VSTO или другой на основе COM надстройка подход. С Excel-Dna вы можете создать макрос, который подключается к кнопке меню или ленты, которая считывает диапазон, обрабатывает его и записывает обратно в диапазон в Excel. Все с использованием собственного интерфейса Excel из C # - не COM-объект в поле зрения.
Я сделал небольшую тестовую функцию, которая переносит текущий выбор в массив, возводит в квадрат каждое число в массиве и записывает результат в лист 2, начиная с ячейки A1. Вам просто нужно добавить (бесплатную) среду выполнения Excel-ДНК, которую вы можете загрузить с http://exceldna.codeplex.com .
Я прочитал в C #, обработал и записал обратно в Excel диапазон в миллион ячеек менее чем за секунду. Это достаточно быстро для вас?
Моя функция выглядит следующим образом:
using ExcelDna.Integration;
public static class RangeTools {
[ExcelCommand(MenuName="Range Tools", MenuText="Square Selection")]
public static void SquareRange()
{
object[,] result;
// Get a reference to the current selection
ExcelReference selection = (ExcelReference)XlCall.Excel(XlCall.xlfSelection);
// Get the value of the selection
object selectionContent = selection.GetValue();
if (selectionContent is object[,])
{
object[,] values = (object[,])selectionContent;
int rows = values.GetLength(0);
int cols = values.GetLength(1);
result = new object[rows,cols];
// Process the values
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (values[i,j] is double)
{
double val = (double)values[i,j];
result[i,j] = val * val;
}
else
{
result[i,j] = values[i,j];
}
}
}
}
else if (selectionContent is double)
{
double value = (double)selectionContent;
result = new object[,] {{value * value}};
}
else
{
result = new object[,] {{"Selection was not a range or a number, but " + selectionContent.ToString()}};
}
// Now create the target reference that will refer to Sheet 2, getting a reference that contains the SheetId first
ExcelReference sheet2 = (ExcelReference)XlCall.Excel(XlCall.xlSheetId, "Sheet2"); // Throws exception if no Sheet2 exists
// ... then creating the reference with the right size as new ExcelReference(RowFirst, RowLast, ColFirst, ColLast, SheetId)
int resultRows = result.GetLength(0);
int resultCols = result.GetLength(1);
ExcelReference target = new ExcelReference(0, resultRows-1, 0, resultCols-1, sheet2.SheetId);
// Finally setting the result into the target range.
target.SetValue(result);
}
}
Я делал подобные вещи раньше в Bugzilla, и решение, которое я нашел, не было реализовывать иерархические «баги истории» и т.п. мы также решили, что это вызовет путаницу и слишком сложно для того, что мы хотели. Решение, которое я использовал раньше, заключалось в том, чтобы просто указать номер пользовательской истории в описании ошибки; вы также можете добавить туда ссылку, чтобы упростить разыменование. Это немного лоскутно, но работает довольно хорошо.
Я бы сказал, что если вашим пользовательским историям требуется более одного случая ошибок - они слишком велики. С хорошей абстракцией требуемой функциональности вы можете разделить свои пользовательские истории на более мелкие, для которых требуется только один случай для каждой истории, а затем спланировать и действовать таким образом.
Мы попытались использовать подход @McWafflestix описывает со ссылками из кейсов на официальный (вики) документ пользовательской истории, но через некоторое время мы обнаружили, что создание небольших пользовательских историй лучше - это также приводит к лучшему дизайну приложения, потому что каждая пользовательская история реализован максимально абстрактно, обеспечивая лучшую тестируемость и ремонтопригодность кода.