演练:使用 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# 脚本

  1. 首先,创建 F# 脚本。在**“文件”菜单上指向“新建”,然后单击“文件”。在“新建文件”对话框中,选择“安装”模板列表下“常规”类别的“脚本”,然后选择“F# 脚本文件”。单击“打开”**创建文件,然后将文件保存为 RateAnalysis.fsx。

  2. 使用 .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 复制到浏览器中,则会返回一个逗号分隔值列表,其中包含由美联储发布的日期和利率。

  3. 现在,您将通过使用 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]
      
      >
      
  4. 接下来,通过使用 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# Interactive”窗口

  5. 现在,您将编写 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])
    
  6. 现在,您将为此功能指定一个名称。从 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。注意下列事项:

    现在代码与以下内容类似。

    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
    
  7. 现在,您将对新输入使用此功能。选择所有代码,然后按 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 的脚本。您可以使用脚本文件以交互方式测试库代码。
  1. 现在,您将创建一个公开所需的功能的 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 
    

    注意下列事项:

    • F# 支持面向对象的编程概念。有关更多信息,请参见类 (F#)继承 (F#) 和 F# 语言参考中的其他相关主题。
  2. 要生成项目,请按 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 ==========
      
  3. 若要添加 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 中的值。

  4. 若要调试该应用程序,请按 F11 生成该应用程序,在调试器中启动该应用程序,然后单步执行到所执行代码的第一行。按 F11 若干次直至单步执行到 GetAnalyzers 成员的主体中的 F# 代码。注意下列事项:

    • 可以很容易地从 C# 代码单步执行到 F# 代码。

    • F# 中的每个表达式在调试器中都是一个执行步骤。

    • “局部变量”窗口显示 maturities 的值。

    • 继续按 F11,逐句通过该应用程序其余的计算。

    • “运行到光标处”“设置下一语句”“插入断点”、**“添加监视”“转到反汇编”**这类调试器命令全部按预期方式工作。

部署应用程序

  1. 如果仍在调试,请通过选择 Shift+F5 键或通过打开**“调试”** =菜单然后选择**“停止调试”**停止调试。

  2. 打开 CSharpDriver 项目的快捷菜单,然后选择**“属性”**。

  3. 在项目设计器中,选择**“发布”**选项卡,将显示部署应用程序的选项。

  4. 选择**“发布向导”**按钮。

    启动发布向导,且第一个屏幕询问您希望将文件发布到的位置。

  5. 在文本框中,在发布时,希望安装应用程序的文件放置在本地磁盘上指定的文件位置,或选择**“浏览”**按钮可以导航到该位置。

  6. 选择**“完成”按钮接受任何默认生成可以赋给客户端的标准安装,或选择“接下来”**按钮查看其他发布选项。

    安装程序可执行文件和支持文件发布到您指定的位置。

后续步骤

通过阅读演练:您的首个 F# 程序来开始编写 F# 代码,或者通过阅读作为一类值的函数 (F#)来了解 F# 中的函数。您可以通过阅读 F# 语言参考来探索 F# 语言。

请参见

其他资源

Visual F# 示例和演练

Visual F# 示例和演练