强制使用mutable来读取Excel ThisWorkbook.Names?

我想获得一个基于F#的加载项的Excel命名范围中的数据。 我想能够在工作簿中的任何地方使用命名的范围,而不仅仅是一个特定的工作表。

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集合performance不佳。 例如

 let name_seq = Seq.toList name_list 

“名称”types与“seq <'a>”types不兼容

有没有更多的F#惯用的方式呢?

您应该使用Seq.castname_list为一个types化的序列。

优点是显而易见的; 你有更好的与F#的互操作性,可以使用Seq模块中的高阶函数,而不是循环的必要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) 

返回types现在是obj[,] option ,它为您提供免费的types安全。

我无法使用Seq。 直接因为不兼容的types。 我做了这个函数,目的是将集合转换为F#列表,然后我可以像上面那样处理。 它编译好,但我没有testing,因为…

 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 

…然后我find一个更简单的方法直接做到这一点:

 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 

谢谢你的帮助!