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

时间:2012-07-07 19:17:27

标签: excel collections f# 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集合表现不佳。例如

let name_seq = Seq.toList name_list

给出

  

类型'名称'与'seq&lt;'a&gt;'类型不兼容

是否有更多F#惯用的方式?

2 个答案:

答案 0 :(得分: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,可免费为您提供类型安全。

答案 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

感谢帮助人员!