2012-07-07 38 views
1

我想獲取一個基於F#的加載項的Excel命名範圍中的數據。我希望能夠在工作簿中的任何位置使用命名範圍,而不僅僅是特定的工作表。被迫使用mutable來讀取Excel ThisWorkbook.Names?

let xlRange (xl:Microsoft.Office.Interop.Excel.Application, name:string) = 
    let name_list = xl.ThisWorkbook.Names:Microsoft.Office.Interop.Excel.Names 
    let mutable result=null 
    for n in name_list do 
     let nn = n :?> Microsoft.Office.Interop.Excel.Name 
     if nn.Name = name then 
      let range=nn.RefersToRange 
      result <- range.Value2 :?> obj[,] 
    result 

上面的代碼工作,但我不喜歡它,因爲我不得不使用一個可變的和命令式的風格。問題是Excel.Names集合表現不佳。例如

let name_seq = Seq.toList name_list 

類型「名」是不是與類型兼容「序列<‘一>’

是否有這樣做的更多的F#習慣的方法?

+0

嘗試'Seq.toList(Seq.cast name_list)',甚至可能指定一個類型(即'let name_seq:... = ...')。 – 2012-07-07 19:23:14

回答

1

您應該使用Seq.castname_list轉換爲類型序列。

優點很明顯;您可以更好地與F#進行互操作,並且可以使用Seq module中的高階函數,而不是必需的for循環。

let xlRange (xl: Microsoft.Office.Interop.Excel.Application, name: string) = 
    xl.ThisWorkbook.Names 
    |> Seq.cast<Microsoft.Office.Interop.Excel.Name> 
    |> Seq.tryPick (fun n -> if n.Name = name 
          then Some (n.RefersToRange.Value2 :?> obj[,]) 
          else None) 

的返回類型現在是obj[,] option這給你免費的類型安全。

+0

感謝這是我第一次嘗試,但我得到'類型'名稱'不兼容'IEnumerable'類型 – 2012-07-09 10:27:01

0

我無法使用Seq。直接因爲不兼容的類型。 我做了這個函數,目的是將集合轉換爲一個F#列表,然後我可以像上面那樣處理。它編譯罰款,但我沒有,因爲考...

let xlNamesToList names = 
    let rec xlNameList_r (names:Microsoft.Office.Interop.Excel.Names) idx = 
     if idx>names.Count then // should this be >= ? 
      [] 
     else 
      names.Item(idx)::xlNameList_r names (idx+1) 
    xlNameList_r names 0 

...然後我發現了一個更簡單的辦法直接做到這一點:

let xlRange (xl:Microsoft.Office.Interop.Excel.Application, name:string) = 
    try 
     let r=xl.ThisWorkbook.Names.Item(name :> obj).RefersToRange 
     Some(r.Value2 :?> obj[,]) 
    with 
     | _ -> None 

感謝您的幫助傢伙!