Необходимо смотреть на Redmine ( http://www.redmine.org/ ). Это имеет все функции, которые Вы упоминаете и т.д. Можно разместить его самостоятельно vps (я делаю).
Почему бы просто не изменить свой индекс?
List<string> RowHeadings = new List<string>();
for (int Row = 1; Row <= MaxRows; Row++) {
if (ExcelData[Row, 1] != null)
RowHeadings.Add(ExcelData[Row, 1]);
}
Изменить: Вот метод расширения, который создаст новый массив с нулевым отсчетом из исходного (в основном он просто создает новый массив на один элемент меньше и копирует в этот новый массив все элементы, кроме первый элемент, который вы все равно пропускаете):
public static T[] ToZeroBasedArray<T>(this T[] array)
{
int len = array.Length - 1;
T[] newArray = new T[len];
Array.Copy(array, 1, newArray, 0, len);
return newArray;
}
При этом вам нужно учитывать, стоит ли штраф (пусть даже небольшой) за создание нового массива улучшения читабельности кода. Я не делаю суждения (вполне возможно, оно того стоит). Я просто убеждаюсь, что вы не запускаете этот код, если это повлияет на производительность вашего приложения.
Создайте оболочку для массива ExcelData
с this [,]
indexer и выполните там логику перебазирования. Примерно так:
class ExcelDataWrapper
{
private object[,] _excelData;
public ExcelDataWrapper(object[,] excelData)
{
_excelData = excelData;
}
public object this[int x, int y]
{
return _excelData[x+1, y+1];
}
}
Так как вам нужна строка
, чтобы оставаться как есть (на основе ваших комментариев), вы можете просто ввести другую переменную цикла:
List<string> RowHeadings = new List<string>();
string [,] Results = new string[MaxRows, 1]
for (int Row = 0, SrcRow = 1; SrcRow <= MaxRows; Row++, SrcRow++) {
if (ExcelData[SrcRow, 1] != null)
RowHeadings.Add(ExcelData[SrcRow, 1]);
...
...
Results[Row, 0] = ExcelData[SrcRow, 1];
}
Почему бы не использовать:
for (int Row = 1; Row <= MaxRows; Row++) {
Или что-то мне не хватает?
РЕДАКТИРОВАТЬ: поскольку оказывается, что чего-то не хватает, я бы использовал другой счетчик (начиная с 0) для этой цели и используйте индекс строки на основе 1 для массива. Не рекомендуется использовать индекс для других целей, кроме индекса в целевом массиве.
Вам слишком сложно изменить счетчик цикла?
for (int Row = 1; Row <= MaxRows; Row++)
Если диапазон счетчика правильный, вам не нужно добавлять 1 к чему-либо внутри цикла, чтобы не потерять читаемость . Будьте проще.
Вы можете использовать сторонний компонент, совместимый с Excel, такой как SpreadsheetGear для .NET , который имеет дружественные к .NET API, включая индексирование на основе 0 для таких API, как IRange [int rowIndex , int colIndex].
Такие компоненты также будут намного быстрее, чем API Excel почти во всех случаях.
Заявление об ограничении ответственности: Я владею SpreadsheetGear LLC
Я согласен с тем, что работать с массивами base-1 из .NET может быть сложно. Это также потенциально подвержено ошибкам, так как вы должны мысленно делать сдвиг каждый раз, когда используете его, а также правильно помнить, какие ситуации будут с базой 1, а какие - с базой 0.
Самый эффективный подход - это просто сделайте эти умственные сдвиги и индексируйте соответствующим образом, используя базу-1 или базу-0, если требуется.
Я лично предпочитаю преобразовывать двумерные массивы с основанием 1 в двумерные массивы с основанием 0. Это, к сожалению, требует снижения производительности при копировании массива в новый массив, так как нет никакого способа восстановить массив на месте.
Вот метод расширения, который может сделать это для 2D-массивов, возвращаемых Excel :
public static TResult[,] CloneBase0<TSource, TResult>(
this TSource[,] sourceArray)
{
If (sourceArray == null)
{
throw new ArgumentNullException(
"The 'sourceArray' is null, which is invalid.");
}
int numRows = sourceArray.GetLength(0);
int numColumns = sourceArray.GetLength(1);
TResult[,] resultArray = new TResult[numRows, numColumns];
int lb1 = sourceArray.GetLowerBound(0);
int lb2 = sourceArray.GetLowerBound(1);
for (int r = 0; r < numRows; r++)
{
for (int c = 0; c < numColumns; c++)
{
resultArray[r, c] = sourceArray[lb1 + r, lb2 + c];
}
}
return resultArray;
}
А затем вы можете использовать это так:
object[,] array2DBase1 = (object[,]) MySheet.UsedRange.get_Value(Type.Missing);
object[,] array2DBase0 = array2DBase1.CloneBase0();
for (int row = 0; row < array2DBase0.GetLength(0); row++)
{
for (int column = 0; column < array2DBase0.GetLength(1); column++)
{
// Your code goes here...
}
}
Для массивов большого размера вы можете не захотеть этого делать,