【问题标题】:Convert Excel Range to C# Array将 Excel 范围转换为 C# 数组
【发布时间】:2014-03-31 11:37:57
【问题描述】:

我想使用以下代码将 Excel 范围转换为 C# 数组:

System.Array MyRange = (System.Array)range.cells.value;

for (int k = 0; k <= MyRange.Length; k++)
{
    List<service_name> _ml = new List<service_name>();
    for (int j = 1; j < dataitems.Count; j++)
    {
        // enter code here
    }
}

然后像上面的循环一样迭代它。

但是这段代码不起作用,并抛出这个异常:

“无法将 'System.String' 类型的对象转换为 'System.Array' 类型。”

【问题讨论】:

  • 它们至少应该是Range.Cells.Value 这样的大写字母。但是关于您的问题没有足够的信息。请澄清一下。

标签: c# arrays excel


【解决方案1】:

根据我的 Microsoft here 提供的帮助,这就是我在 Excel 中读取和写入数组的方式。

var xlApp=new Microsoft.Office.Interop.Excel.Application();
var wb=xlApp.Workbooks.Open(fn, ReadOnly: false);
xlApp.Visible=true;
var ws=wb.Worksheets[1] as Worksheet;
var r=ws.Range["A2"].Resize[100, 1];
var array=r.Value;
// array is object[1..100,1..1]
for(int i=1; i<=100; i++)
{
    var text=array[i, 1] as string;
    Debug.Print(text);
}
// to create an [1..100,1..1] array use
var array2=Array.CreateInstance(
    typeof(object), 
    new int[] {100, 1}, 
    new int[] {1, 1}) as object[,];

// fill array2
for(int i=1; i<=100; i++)
{
    array2[i, 1] = string.Format("Text{0}",i);
}
r.Value2=array2;

wb.Close(SaveChanges: true);
xlApp.Quit();

【讨论】:

【解决方案2】:

当范围仅包含一个单元格时,会出现原始帖子中的错误消息,因为结果值的类型是变体,实际上可以是数组、双精度、字符串、日期和空值。

一种解决方案可以是检查细胞计数并在恰好一个细胞的情况下采取不同的行动。

我的解决方案创建了一个单元格数组。即使一个或多个单元格为空,这也有效,这可能导致空对象。 (当范围内所有单元格为空时,Range.Cells.Value 为空。)

System.Array cellArray = range.Cells.Cast<Excel.Range>().ToArray<Excel.Range>();

如果您更喜欢列表而不是数组(就像我一样),您可以使用以下代码:

List<Excel.Range> listOfCells = range.Cells.Cast<Excel.Range>().ToList<Excel.Range>();

范围可以是一维或二维的。

最后,如果你肯定需要一个字符串数组,这里是:

string[] strArray = range.Cells.Cast<Excel.Range>().Select(Selector).ToArray<string>();

Selector 函数如下所示:

public string Selector(Excel.Range cell)
{
    if (cell.Value2 == null)
        return "";
    if (cell.Value2.GetType().ToString() == "System.Double")
        return ((double)cell.Value2).ToString();
    else if (cell.Value2.GetType().ToString() == "System.String")
        return ((string)cell.Value2);
    else if (cell.Value2.GetType().ToString() == "System.Boolean")
        return ((bool)cell.Value2).ToString();
    else
        return "unknown";
}

对于我不记得 Value2 可以返回的所有数据类型的情况,我包括了“未知”。如果您发现任何其他类型,请改进此功能。

【讨论】:

    【解决方案3】:

    错误表示该值是一个字符串,所以不能直接转换成数组。

    如果值是例如逗号分隔的字符串,您可以使用 Split 来获取一个数组:

    string[] MyRange = (range.Cells.Value + "").Split(',');
    for (int k = 0; k < MyRange.Length; k++)
    {
        //...loop here...
    }
    

    还修复了你的循环,你会得到 Index Out of Bounds 错误。

    【讨论】:

      【解决方案4】:

      注意:此示例仅适用于多于一个单元格的范围。如果 Range 只是单个单元格 (1x1),Excel 将以特殊方式处理它,并且 range.Value2 不会返回二维数组,而是返回单个值。正是这些类型的特殊情况以及零和非零数组下限会让您抓狂:

      using Excel = Microsoft.Office.Interop.Excel;
      
      private static void Test()
      {
          Excel.Range range = Application.ActiveWorkbook.ActiveSheet.Range["A1:B2"]; // 2x2 array
      
          range.Cells[1, 2] = "Foo"; // Sets Cell A2 to "Foo"
          dynamic[,] excelArray = range.Value2 as dynamic[,]; // This is a very fast operation
          Console.Out.WriteLine(excelArray[1, 2]); // => Foo
      
          excelArray[1, 2] = "Bar";
          range.Value2 = excelArray; // Sets Cell A2 to "Bar", again a fast operation even for large arrays
          Console.Out.WriteLine(range.Cells[1, 2]); // => Bar
      

      请注意,excelArray 的行和列下限为 1:

          Console.Out.WriteLine("RowLB: " + excelArray.GetLowerBound(0)); // => RowLB: 1
          Console.Out.WriteLine("ColLB: " + excelArray.GetLowerBound(1)); // => ColLB: 1
      

      但是,如果你在 C# 中声明一个 newArray 并分配它,那么下限将为 0,但它仍然可以工作:

          dynamic[,] newArray = new dynamic[2, 2]; // Same dimensions as "A1:B2" (2x2)
          newArray[0, 1] = "Foobar";
          range.Value2 = newArray; // Sets Cell A2 to "Foobar"
          Console.Out.WriteLine(range.Cells[1, 2]); // => Foobar
      

      从该范围内获取这个值将为您提供下限为 0 的原始数组:

          range.Cells[1, 2] = "Fubar";
      
          dynamic[,] lastArray = range.Value2 as dynamic[,];
          Console.Out.WriteLine(lastArray[0, 1]); // => Fubar
      
          Console.Out.WriteLine("RowLB: " + lastArray.GetLowerBound(0)); // => RowLB: 0
          Console.Out.WriteLine("ColLB: " + lastArray.GetLowerBound(1)); // => ColLB: 0
      }
      

      使用 Excel Interop 可能会让人望而生畏,因为代码库中有很多这样的特殊情况,但我希望这至少有助于澄清这一点。

      【讨论】:

        【解决方案5】:

        谈话迟到了,但这里有一个方法可以做到这一点:

        static string[][] GetStringArray(Object rangeValues)
        {
            string[][] stringArray = null;
        
            Array array = rangeValues as Array;
            if (null != array)
            {
                int rank = array.Rank;
                if (rank > 1)
                {
                    int rowCount = array.GetLength(0);
                    int columnCount = array.GetUpperBound(1);
        
                    stringArray = new string[rowCount][];
        
                    for (int index = 0; index < rowCount; index++)
                    {
                        stringArray[index] = new string[columnCount-1];
        
                        for (int index2 = 0; index2 < columnCount; index2++)
                        {
                            Object obj = array.GetValue(index + 1, index2 + 1);
                            if (null != obj)
                            {
                                string value = obj.ToString();
        
                                stringArray[index][index2] = value;
                            }
                        }
                    }
                }
            }
        
            return stringArray;
        }
        

        调用:

        string[][] rows = GetStringArray(range.Cells.Value2);
        

        【讨论】:

          【解决方案6】:

          问题是因为,当你的范围变成单个单元格时,“range.value”/“range.cell.value”表示字符串值,这个字符串不能放入对象数组中。 因此,请检查您的范围是否只有一个或多个单元格并按照此操作

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-04-09
            • 2010-10-15
            • 1970-01-01
            • 2017-04-28
            • 2012-05-11
            • 2016-02-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多