演练:使用 Visual F# 创建、调试和部署应用程序
本演练将带给您在 Visual Studio 2010 中使用 F# 和 .NET Framework 4 的体验。
在本演练中,您将通过对美国国债利率数据的历史分析这样一个示例,了解如何开始使用 Visual Studio 2010 来编写 F# 应用程序。 首先,您将使用 F# 交互窗口来对数据进行一些快速分析,然后编写和测试一些代码来分析数据,最后添加一个 C# 前端来探索如何将 F# 代码与其他 .NET 语言进行集成。
系统必备
您需要以下组件来完成本演练:
- Visual Studio 2010
提示
对于在以下说明中使用的某些 Visual Studio 用户界面元素,您的计算机可能会显示不同的名称或位置。这些元素取决于您所使用的 Visual Studio 版本和您所使用的设置。有关更多信息,请参见 Visual Studio 设置。
创建 F# 脚本
首先,创建 F# 脚本。 在**“文件”菜单上指向“新建”,然后单击“文件”。 在“新建文件”对话框中,选择“已安装的模板”列表中的“脚本”,然后选择“F# 脚本文件”。 单击“打开”**创建文件,然后将文件保存为 RateAnalysis.fsx。
使用 .NET 和 F# API 从美联储的 Internet 网站访问数据。 键入下列代码。
open System.Net open System.IO let url = sprintf "http://www.federalreserve.gov/releases/h15/data/business_day/H15_TCMNOM_Y10.txt" let req = WebRequest.Create(url, Timeout = 10000000) let resp = req.GetResponse() let stream = resp.GetResponseStream() let reader = new StreamReader(stream) let csv = reader.ReadToEnd()
注意下列事项:
字符串和关键字用不同的颜色显示。
在您每次键入一个句点 (.) 之后,将会出现一个完成列表。
在键入一个标识符的过程中,通过使用键盘快捷键 Ctrl+空格或 Ctrl+J,可以让 Visual Studio 完成方法名称和其他标识符。 当使用 Ctrl+J 时,将会出现一个完成列表。
将鼠标指针停留在代码中的任何标识符上时,您将会看到一个包含有关该标识符的信息的工具提示。
如果在光标位于 WebRequest 中时按 F1,则将出现预期的文档。
如果在光标位于 let 中时按 F1,则将出现预期的文档。
默认情况下,将引用 mscorlib.dll、System.dll 和 System.Windows.Forms.dll 中的类型和命名空间。
在此处设置的 Timeout 值是一个属性,而不是构造函数参数。 F# 允许您通过此方式设置属性值。
如果将示例中的 URL 复制到浏览器中,则会返回一个逗号分隔值列表,其中包含由美联储发布的日期和利率。
现在,您将通过使用 F# 交互来执行代码。 选择所有代码(使用鼠标或按 Ctrl+A)并右击,然后单击**“发送到 Interactive”**。 (或者,也可以按 Alt+Enter。)
如果“F# Interactive”窗口此前尚未显示,此时将会出现。
代码成功执行。
“F# Interactive”窗口中将会出现以下内容。
val url : string = "http://www.federalreserve.gov/releases/h15/data/business_day/"+[18 chars] val req : System.Net.WebRequest val resp : System.Net.WebResponse val stream : System.IO.Stream val reader : System.IO.StreamReader val csv : string = " ,Instrument,"U.S. government securities/Treasury constant m"+[224452 chars] >
接下来,通过使用 F# Interactive 来检查数据。 在 F# Interactive 提示符处,键入 csv;;,然后按 Enter。 键入 csv.Length;;,然后按 Enter。 注意下列事项:
数据是最新的。
F# Interactive 显示字符串 csv 的值及其长度,如下所示。
07/10/2009, 3.32 07/13/2009, 3.38 07/14/2009, 3.50 07/15/2009, 3.63 " > csv.Length;; val it : int = 224513
下图所示为“F# Interactive”窗口。
“F# Interactive”窗口
现在,您将编写 F# 代码来分析 CSV(逗号分隔的值)数据。 CSV 文件是因其包含以逗号分隔的值而得名的。 在代码编辑器中,添加以下代码。 添加每一行时,选择在本节中前面已添加的代码和刚添加的代码行,然后按 Alt+Enter 以查看部分结果。 注意下列事项:
在您键入一个句点之后,IntelliSense 会提供帮助信息,即使在复杂的嵌套表达式中也同样如此。
当代码未完成(或不正确)时,将会显示红色波浪下划线,指示代码中出现语法和语义错误。
通过使用管道运算符(|>)来创建管道。 管道运算符接收一个表达式的返回值,并将其用作下一行的函数的参数。 通过使用管道和 F# Interactive,可以很轻松地部分执行数据处理代码。
let interest = csv.Split([|'\n'|]) |> Seq.skip 8 |> Seq.map (fun line -> line.Trim()) |> Seq.filter (fun line -> not (line.EndsWith("ND"))) |> Seq.filter (fun line -> not (line.Length = 0)) |> Seq.map (fun line -> line.Split([|','|])) |> Seq.map ( fun values -> System.DateTime.Parse(values.[0]), float values.[1])
现在,您将为此功能指定一个名称。 从 url 的定义中移除 10 并将其替换为 %d,以使字符串文本成为格式字符串。 在格式字符串之后添加 maturity。 选择除这一新行之外的所有代码,然后按 Tab。 在缩进的代码块上方,添加 let loadRates maturity =。 在缩进代码块的结尾,添加 interest。 注意下列事项:
缩进在 F# 中是有意义的。 缩进指示嵌套级别。
Tab 与提取方法重构 (C#) 非常相似。
现在代码与以下内容类似。
open System.Net open System.IO let loadRates maturity = let url = sprintf "http://www.federalreserve.gov/releases/h15/data/business_day/H15_TCMNOM_Y%d.txt" maturity let req = WebRequest.Create(url, Timeout = 10000000) let resp = req.GetResponse() let stream = resp.GetResponseStream() let reader = new StreamReader(stream) let csv = reader.ReadToEnd() let interest = csv.Split([|'\n'|]) |> Seq.skip 8 |> Seq.map (fun line -> line.Trim()) |> Seq.filter (fun line -> not (line.EndsWith("ND"))) |> Seq.filter (fun line -> not (line.Length = 0)) |> Seq.map (fun line -> line.Split([|','|])) |> Seq.map ( fun values -> System.DateTime.Parse(values.[0]), float values.[1]) interest
现在,您将对新输入使用此功能。 选择所有代码,然后按 Alt+Enter 以使用 F# Interactive 来执行代码。 在 F# Interactive 提示符处,对其他到期利率调用新的 loadRates 函数:1、2 和 5(以年为单位)。 注意下列事项:
以前的定义在 F# Interactive 中不会丢失,但提供了新的定义。
复杂的结构化数据通过特殊的打印功能来呈现。
使用 F# 开发组件
创建一个库项目来公开已创建的功能。 在**“文件”菜单上指向“新建”,然后单击“项目”。 在“新建项目”对话框中,选择“已安装的模板”列表中的“Visual F#”,然后选择“F# 库”创建新的库项目。 将项目命名为 RateAnalysis。 从 RateAnalysis.fsx 中复制您以前创建的代码,并将其粘贴到 Module1.fs 中。 将 Module1.fs 中的模块声明从模块 Module1 更改为模块 RateLoader。 在“解决方案资源管理器”**中,将 Module1.fs 重命名为 RateLoader.fs。 注意下列事项:
- 默认的 F# 库模板提供一个扩展名为 .fs 的代码文件和一个扩展名为 .fsx 的脚本。 您可以使用脚本文件以交互方式测试库代码。
下图显示了带有若干可用的 F# 选项的**“新建项目”**对话框。 选择 F# 库项目模板。
F# 模板选项
现在,您将创建一个公开所需的功能的 F# 类。 在**“解决方案资源管理器”中,右击项目,指向“添加”,然后单击“新建项”。 在“添加新项”对话框中,选择“F# 源文件”。 将文件命名为 Analyzer.fs。 在“解决方案资源管理器”中右击“Script.fsx”,然后单击“下移”**。 (另外,也可以按 Alt+向下键。)将下面的代码粘贴到 Analyzer.fs 中:
module RateAnalysis.Analyzer open RateLoader /// Provides analysis of historical interest rate data. type Analyzer(ratesAndDates) = let rates = ratesAndDates |> Seq.map snd /// Construct Analyzer objects for each maturity category. static member GetAnalyzers(maturities) = maturities |> Seq.map loadRates |> Seq.map (fun ratesAndDates -> new Analyzer(ratesAndDates)) member sa.Min = let date, minRate = (Seq.minBy (fun (_, rate) -> rate) ratesAndDates) (minRate, date.ToString("d")) member sa.Max = let date, maxRate = (Seq.maxBy (fun (_, rate) -> rate) ratesAndDates) (maxRate, date.ToString("d")) member sa.Current = rates |> List.ofSeq |> List.rev |> List.head
注意下列事项:
现在,您将生成 XML 文档注释。 在**“解决方案资源管理器”中右击该项目,再单击“属性”。 在“生成”选项卡上,选中页面底部的“XML 文档文件”**复选框。 注意下列事项:
可以为任何 F# 程序集生成 XML 文档。
默认情况下,XML 文档会生成到输出路径中。
要生成项目,请按 Ctrl+Shift+B 或 F6。 注意下列事项:
项目成功生成。
“错误列表”窗口未显示任何错误。
输出目录包含 .dll、.pdb 和 .xml 文件。
“输出”窗口显示以下内容:
------ Build started: Project: RateAnalysis, Configuration: Debug Any CPU ------ C:\Program Files (x86)\Microsoft F#\v4.0\fsc.exe -o:obj\Debug\RateAnalysis.exe -g --debug:full --noframework --define:DEBUG --define:TRACE --optimize- --tailcalls- -r:"C:\Program Files (x86)\Microsoft F#\v4.0\FSharp.Core.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll" --target:exe --warn:3 --warnaserror:76 --vserrors --utf8output --fullpaths --flaterrors Program.fs RateLoader.fs ValueAnalyzer.fs RateAnalysis -> C:\Users\ghogen\Documents\Visual Studio 10\Projects\RateAnalysis\RateAnalysis\bin\Debug\RateAnalysis.exe ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
若要添加 C# 客户端应用程序,请右击解决方案节点,指向**“添加”,然后单击“新建项目”。 在“添加新建项目”对话框中,选择“已安装的模板”列表中的“Visual C#”,然后选择“控制台应用程序”。 您可能需要展开“其他语言”节点。 将项目命名为 CSharpDriver。 右击此项目的“引用”节点,然后单击“添加引用”。 在“添加引用”对话框的“项目”选项卡上,选择“RateAnalysis”,然后单击“确定”。 右击“CSharpDriver”项目节点,然后单击“设为启动项目”**。 在 C# 应用程序的 Main 方法体中键入以下代码。 注意下列事项:
可以在 C# 和 F# 之间添加项目对项目的引用。
可以像任何其他类型一样,从 C# 中使用通过 F# 定义的命名空间和类型。
F# 文档注释在 C# IntelliSense 中可用。
C# 可以从 F# API 中访问元组返回值。 元组是 .NET Framework 4 Tuple 值。
var maturities = new[] { 1, 2, 5, 10 }; var analyzers = RateAnalysis.Analyzer.Analyzer.GetAnalyzers(maturities); foreach (var item in analyzers) { Console.WriteLine("Min = {0}, \t Max = {1}, \t Current = {2}", item.Min, item.Max, item.Current); } Console.WriteLine("Press Enter to exit."); Console.ReadLine();
若要调试该应用程序,请按 F11 生成该应用程序,在调试器中启动该应用程序,然后单步执行到所执行代码的第一行。 按 F11 若干次直至单步执行到 GetAnalyzers 成员的主体中的 F# 代码。 注意下列事项:
可以很容易地从 C# 代码单步执行到 F# 代码。
F# 中的每个表达式在调试器中都是一个执行步骤。
“局部变量”窗口显示 maturities 的值。
继续按 F11,逐句通过该应用程序其余的计算。
“运行到光标处”、“设置下一语句”、“插入断点”、**“添加监视”和“转到反汇编”**这类调试器命令全部按预期方式工作。
部署 F# 应用程序:
在此步骤中,将设置项目以 .NET Framework 的不同版本为目标。 在**“解决方案资源管理器”中,右击 F# RateAnalysis 项目,然后单击“属性”。 在“应用程序”选项卡上,将“目标框架”设置更改为“.NET Framework 3.5”**。 注意下列事项:
F# 允许您以 .NET Framework 的不同版本为目标。
更改目标框架要求重新加载项目。
更改目标框架之后,一些程序集引用在**“添加引用”**对话框中不再启用,并且无法使用。
在 C# 项目中,您必须添加对以 .NET Framework 2.0 为目标的 FSharp.Core 程序集版本的引用。当您以 .NET Framework 的 3.0 和 3.5 版本为目标时,还应使用 .NET Framework 2.0 版本。 在**“解决方案资源管理器”中,右击“引用”节点,然后单击“添加引用”。 在“.NET”选项卡上,选择 FSharp.Core 版本 2.0.0.0,然后单击“确定”**。 重新生成解决方案。
若要设置系统必备组件,请单击 CSharpDriver 中的**“属性”节点。 在“发布”选项卡上,单击“系统必备组件”按钮,然后在“系统必备组件”对话框中,选中“Microsoft Visual F# Runtime for .NET 2.0”**复选框。 注意下列事项:
F# 具有一个与 .NET Framework 不同的运行时包。
当部署使用 F# 的应用程序时,必须将此运行时包显式添加为系统必备组件。
现在提供了两个运行时包:适用于 .NET Framework 版本 2.0、3.0 和 3.5 的 2.0 版本和适用于 .NET Framework 4 的 4.0 版本。
使用 ClickOnce 部署 C# 应用程序。 右击 CSharpDriver 项目,然后单击**“发布”。 在发布向导中单击“完成”**。 运行生成的 CSharpDriver.application。 注意下列事项:
Visual F# 运行时包随应用程序附带。
运行该应用程序时,会安装 F# 运行时包并成功执行该应用程序。
后续步骤
通过阅读演练:您的首个 F# 程序来开始编写 F# 代码,或者通过阅读作为一类值的函数 (F#)来了解 F# 中的函数。 您可以通过阅读 F# 语言参考来探索 F# 语言。