我正在尝试在基于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集合表现不佳。例如
let name_seq = Seq.toList name_list
给出
类型'名称'与'seq&lt;'a&gt;'类型不兼容
是否有更多F#惯用的方式?
答案 0 :(得分:1)
您应该使用Seq.cast
将name_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
,可免费为您提供类型安全。
答案 1 :(得分: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
感谢帮助人员!