首页 > 代码库 > 9.5.1 处理记录和成员
9.5.1 处理记录和成员
9.5.1 处理记录和成员
我们先从一个基本的例子开始。在本章的第一节,我们已经知道如何为表示矩形的 Rect 类型添加成员。现在,我们要在 C# 中使用这个类型。首先,我们需要创建一个新的 F# 库项目,添加源文件(例如,export.fs),代码在清单 9.20。
清单 9.20 把 F# 类型编译成库(F#)
namespace Chapter09.FSharpExport [1]
open System
open System.Drawing
type Rect =
{ Left : float32; Width : float32 | [2]
Top : float32; Height :float32 } |
member x.Deflate(wspace, hspace) = |
{ Top = x.Top + wspace;Height = x.Height - (2.0f * hspace) |
Left =x.Left + hspace; Width = x.Width - (2.0f * wspace) } | [3]
member x.ToRectangleF () = |
RectangleF(x.Left,x.Top, x.Width, x.Height) |
可以看到,我们添加了一行代码指定 .NET 命名空间[1]。这个命名空间会包含所有在这个文件中的类型声明(在本例中,只有一个类型,Rect)。这个类型将很容易从 C# 中使用,因为,记录[2]的字段将成为属性,成员成为方法。
下一步,我们要添加一个新的 C# 项目到这个解决方案。添加对这个 F# 项目的引用,与引用其他C# 类库的做法完全相同,但是,还应该添加对 FSharp.Core.dll 程序集的引用,这是 F# 再发行库,包含了 F# 核心函数和类型。在配置项目之后,看到的应该类似图 9.3,该图还显示了本章的其他 F# 类型,出现在 C# 的智能感知中。
图 9.3 添加对 F# 库的引用后,可以在智能感知中看到这个 F# 库中的类型。F# 记录类型 Rect 被编译为普通的类。
如果使用过智能感知,会看到 F# 类型出现的命名空间,就是我们在源代码中指定的。智能感知还显示这个类型有哪些属性和方法,所以,在不需要进一步帮助的情况下,确保能够使用。出于完整性,清单 9.21 给出了一个例子。
清单 9.21 使用F# 库中的类型 (C#)
using System;
using Chapter09.FSharpExport;
class Program {
static void Main(string[] args) {
var rc1 = new Rect(0.0f,100.0f, 0.0f, 50.0f); [1]
var rc2 =rc1.Deflate(20.0f, 10.0f); [2]
Console.WriteLine("({0}, {1}) - ({2}, {3})",
rc2.Left,rc2.Top, rc2.Width, rc2.Height);
}
}
清单 9.21 的代码首先创建 Rect 类型的一个实例。它使用的构造函数,是由 F# 编译器自动生成的[1],相当于创建记录的 F# 代码。我们必须在构造记录时,指定所有字段的值,因为类型是不可变的,以后就不能改变了。下一步调用Deflate方法[2],这就是一个非常普通的方法,虽然它是以纯函数风格实现的,所以,它返回了一个新的 Rect 值,而不是改变现有的值。最后,输出返回的矩形信息,这也是容易的,因为记录字段公开为 .NET 属性。
注意
我们已经看到在 C# 中在引用 F# 的项目,因为这是很常见的情形,我们想明确地显示两种语言如何很好地结合在一起,当 F# 代码使用对象类型时。也能在 F# 应用程序中引用 F# 库,步骤是一样的:为 F# 库指定命名空间,在 Visual Studio 中添加引用,在 F# 应用程序中添加适当的 open 指令。值得注意的是,当在 F# 中引用 F# 库时,编译器能知道这个库是用F# 创建的,因此,所有构造(如差别联合或函数)都可以通常常的 F# 方式访问。
在 C# 中使用 Rect 类型相当简单,图 9.3 显示了本章的其他类型。F# 的接口声明(ClientTest)表现为普通的 .NET 接口,因此,互操作非常平滑。如果我们想导出高阶函数或值,又该如何呢?这两种构造在 C# 中会是什么样子呢?
9.5.1 处理记录和成员