使用COM 风格的编程接口
如果不直接使用 COM 库,不创建自己的包装,那么更可能的是使用 COM 风格的编程接口。这是因为现在许多开发商发布应用程序时,提供了首选的互操作程序集(Primary Interop Assemblies),这是预先创建的 COM 包装,因此,我们就不需要再自己考虑用 TlbImp.exe 来创建包装了。
注意
更多有关首选的互操作程序集的内容,可以在 MSDN 上找到,http://msdn.microsoft.com/en-us/library/aax7sdch.aspx 。
虽然首选的互操作程序集本质上就是 .NET 程序集,但是,通常有一些特殊的地方需要注意,比如:
某些数组和集合经常从 1 开始,而不是 0;
经常有一些方法,会有大量的可选参数;
许多属性和方法会返回对象(object)类型,产生的结果对象需要强制转换成真正的类型;
COM 类包含非托管的资源,需要处理(dispose),然而,这些类没有实现标准的 .NET IDisposable 接口,因此,在 F# 的 use 绑定中就不能使用;不过,我们能够使用 F# 的对象表达式很容易地就实现了 IDisposable。
F# 和 COM 进行交互与 C# 的关键不同在于,我们必须总是要创建对象的实例,而非接口。这听趚有点奇怪,但是,在 COM 库中,每一个对象通常都有一个接口,有一个实现接口的类。在 C# 中,如果使用关键字 new 尝试创建 COM 接口的实例,的COM posablesable 编译器会自动定向到(redirect)调用对应的类,而在 F#中就不是这样。
与 Microsoft Office 交互可能是使用 COM 风格库的最常见理由。下面的清单是读取 Excel 电子表格的信息。
open System
open Microsoft.Office.Interop.Excel
let main() =
// initalize an excel application
let app = new ApplicationClass()
// load a excel work book
let workBook =app.Workbooks.Open(@"Book1.xls",ReadOnly = true)
// ensure work book is closed corectly
use bookCloser ={ new IDisposable with
member x.Dispose() = workBook.Close() }
// open the first worksheet
let worksheet =workBook.Worksheets.[1] :?> _Worksheet
// get the A1 ceel and all surround cells
let a1Cell =worksheet.Range("A1")
let allCells =a1Cell.CurrentRegion
// load all cells into a list of lists
let matrix =
[ for row inallCells.Rows ->
let row = row:?> Range
[ for cell inrow.Columns ->
let cell = cell :?> Range
cell.Value2] ]
// close the workbook
workBook.Close()
// print the matrix
printfn "%A" matrix
do main()
注意这个示例是如何处理我们前面提到的特殊地方的。我们实现了 IDisposable 并把它绑定到 bookCloser,保证即使在出错的情况下也能关闭工作簿;Open 方法有 15 个参数,但是,我们只用了两个:.Open(@"Book1.xls", ReadOnly = true);第一个工作表的索引是 1:workBook.Worksheets.[1];最后,每一行必须强制向上转换(upcast)才能使用:let row = row :?> Range。