演练:使用 Visual F# 创建、调试和部署应用程序
本演练将带给您在 Visual Studio 中使用 F# 和 .NET Framework 4.5 的体验。
在本演练中,您将通过对美国国债利率数据的历史分析这样一个示例,了解如何开始使用 Visual Studio 来编写 F# 应用程序。 首先,您将使用 F# 交互窗口来对数据进行一些快速分析,然后编写和测试一些代码来分析数据,最后添加一个 C# 前端来探索如何将 F# 代码与其他 .NET 语言进行集成。
系统必备
您需要以下组件来完成本演练:
- Visual Studio
备注
对于在以下说明中使用的某些 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/datadownload/Output.aspx?rel=H15&series=bcb44e57fb57efbe90002369321bfb3f&lastObs=&from=&to=&filetype=csv&label=include&layout=seriescolumn" 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/datadownload/Output.aspx?rel=H1"+[107 chars] val req : System.Net.WebRequest val resp : System.Net.WebResponse val stream : System.IO.Stream val reader : System.IO.StreamReader val csv : string = ""Series Description","Market yield on U.S. Treasury securities"+[224219 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 文件是因其包含以逗号分隔的值而得名的。 在代码编辑器中,添加以下代码。 此外,在文件顶部添加 open System.Globalization。 添加每一行时,选择在本节中前面已添加的代码和刚添加的代码行,然后按 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], CultureInfo.CreateSpecificCulture("en-US")), float values.[1])
现在,您将为此功能指定一个名称。 从 url 的定义中移除系列 ID bcb44e57fb57efbe90002369321bfb3f 并将其替换为 %s,以使字符串文本成为格式字符串。 在格式字符串之后添加 seriesID。 选择除打开指令之外的所有代码,然后按 Tab。 在缩进的代码块上方,添加以下代码行。
let loadRates maturity = // The following tuples associate various maturity durations, in years, // with codes defined for treasury bills by the Federal Reserve. let maturitiesMap = Map.ofList [(1, "e30653a4b627e9d1f2490a0277d9f1ac") (2, "c66ea77a2e8f0919c5133c7633065908") (5, "fbb02942bfdbff31a479e98bcbe26388") (10, "bcb44e57fb57efbe90002369321bfb3f") (20, "a1ebeb6e84ca6389772dd054dc980191")] let seriesID = Map.find maturity maturitiesMap
在缩进代码块的结尾,添加 interest。 注意下列事项:
缩进在 F# 中是有意义的。 缩进指示嵌套级别。
Tab 与提取方法重构 (C#) 非常相似。
现在代码与以下内容类似。
open System.Net open System.IO let loadRates maturity = // The following tuples associate various maturity durations, in years, // with codes defined for treasury bills by the Federal Reserve. let maturitiesMap = Map.ofList [(1, "e30653a4b627e9d1f2490a0277d9f1ac") (2, "c66ea77a2e8f0919c5133c7633065908") (5, "fbb02942bfdbff31a479e98bcbe26388") (10, "bcb44e57fb57efbe90002369321bfb3f") (20, "a1ebeb6e84ca6389772dd054dc980191")] let seriesID = Map.find maturity maturitiesMap let url = sprintf "http://www.federalreserve.gov/datadownload/Output.aspx?rel=H15&series=%s&lastObs=&from=&to=&filetype=csv&label=include&layout=seriescolumn" seriesID 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], CultureInfo.CreateSpecificCulture("en-US")), float values.[1]) interest
现在,您将对新输入使用此功能。 选择所有代码,然后按 Alt+Enter 以使用 F# Interactive 来执行代码。 在 F# Interactive 提示符处,对其他到期利率调用新的 loadRates 函数:1、2 和 5(以年为单位)。 注意下列事项:
以前的定义在 F# Interactive 中不会丢失,但提供了新的定义。
复杂的结构化数据通过特殊的打印功能来呈现。
使用 F# 开发组件
创建一个库项目来公开已创建的功能。 在**“文件”菜单上指向“新建”,然后单击“项目”。 在“新建项目”对话框中,选择“已安装”列表中的“Visual F#”,然后选择“F# 库”创建新的库项目。 将项目命名为 RateAnalysis。 从 RateAnalysis.fsx 中复制您以前创建的代码,并将其粘贴到 Library1.fs 中。 将模块声明添加到文件的顶部:module RateLoader。 可在“解决方案资源管理器”**中,将 Library1.fs 重命名为 RateLoader.fs,并保存该文件。 注意下列事项:
- 默认的 F# 库模板提供一个扩展名为 .fs 的代码文件和一个扩展名为 .fsx 的脚本。 您可以使用脚本文件以交互方式测试库代码。
现在,您将创建一个公开所需的功能的 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
注意下列事项:
要生成项目,请按 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 方法体中键入以下代码。
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();
注意下列事项:
可以在 C# 和 F# 之间添加项目对项目的引用。
可以像任何其他类型一样,从 C# 中使用通过 F# 定义的命名空间和类型。
F# 文档注释在 C# IntelliSense 中可用。
C# 可以从 F# API 中访问元组返回值。 元组是 Tuple .NET Framework 4.5 中的值。
若要调试该应用程序,请按 F11 生成该应用程序,在调试器中启动该应用程序,然后单步执行到所执行代码的第一行。 按 F11 若干次直至单步执行到 GetAnalyzers 成员的主体中的 F# 代码。 注意下列事项:
可以很容易地从 C# 代码单步执行到 F# 代码。
F# 中的每个表达式在调试器中都是一个执行步骤。
“局部变量”窗口显示 maturities 的值。
继续按 F11,逐句通过该应用程序其余的计算。
“运行到光标处”、“设置下一语句”、“插入断点”、**“添加监视”和“转到反汇编”**这类调试器命令全部按预期方式工作。
部署应用程序
如果仍在调试,请通过选择 Shift+F5 键或通过打开**“调试”** =菜单然后选择**“停止调试”**停止调试。
打开 CSharpDriver 项目的快捷菜单,然后选择**“属性”**。
在项目设计器中,选择**“发布”**选项卡,将显示部署应用程序的选项。
选择**“发布向导”**按钮。
启动发布向导,且第一个屏幕询问您希望将文件发布到的位置。
在文本框中,在发布时,希望安装应用程序的文件放置在本地磁盘上指定的文件位置,或选择**“浏览”**按钮可以导航到该位置。
选择**“完成”按钮接受任何默认生成可以赋给客户端的标准安装,或选择“接下来”**按钮查看其他发布选项。
安装程序可执行文件和支持文件发布到您指定的位置。
后续步骤
通过阅读演练:您的首个 F# 程序来开始编写 F# 代码,或者通过阅读作为一类值的函数 (F#)来了解 F# 中的函数。 您可以通过阅读 F# 语言参考来探索 F# 语言。