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

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

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

  3. 现在,您将通过使用 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]
      
      >
      
  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 文件是因其包含以逗号分隔的值而得名的。 在代码编辑器中,添加以下代码。 添加每一行时,选择在本节中前面已添加的代码和刚添加的代码行,然后按 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])
    
  6. 现在,您将为此功能指定一个名称。 从 url 的定义中移除 10 并将其替换为 %d,以使字符串文本成为格式字符串。 在格式字符串之后添加 maturity。 选择除这一新行之外的所有代码,然后按 Tab。 在缩进的代码块上方,添加 let loadRates maturity =。 在缩进代码块的结尾,添加 interest。 注意下列事项:

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

    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
    
  7. 现在,您将对新输入使用此功能。 选择所有代码,然后按 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# 库”的“新建项目”对话框

  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. 现在,您将生成 XML 文档注释。 在**“解决方案资源管理器”中右击该项目,再单击“属性”。 在“生成”选项卡上,选中页面底部的“XML 文档文件”**复选框。 注意下列事项:

    • 可以为任何 F# 程序集生成 XML 文档。

    • 默认情况下,XML 文档会生成到输出路径中。

  3. 要生成项目,请按 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 ==========
      
  4. 若要添加 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();
    
  5. 若要调试该应用程序,请按 F11 生成该应用程序,在调试器中启动该应用程序,然后单步执行到所执行代码的第一行。 按 F11 若干次直至单步执行到 GetAnalyzers 成员的主体中的 F# 代码。 注意下列事项:

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

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

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

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

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

部署 F# 应用程序:

  1. 在此步骤中,将设置项目以 .NET Framework 的不同版本为目标。 在**“解决方案资源管理器”中,右击 F# RateAnalysis 项目,然后单击“属性”。 在“应用程序”选项卡上,将“目标框架”设置更改为“.NET Framework 3.5”**。 注意下列事项:

    • F# 允许您以 .NET Framework 的不同版本为目标。

    • 更改目标框架要求重新加载项目。

    • 更改目标框架之后,一些程序集引用在**“添加引用”**对话框中不再启用,并且无法使用。

  2. 在 C# 项目中,您必须添加对以 .NET Framework 2.0 为目标的 FSharp.Core 程序集版本的引用。当您以 .NET Framework 的 3.0 和 3.5 版本为目标时,还应使用 .NET Framework 2.0 版本。 在**“解决方案资源管理器”中,右击“引用”节点,然后单击“添加引用”。 在“.NET”选项卡上,选择 FSharp.Core 版本 2.0.0.0,然后单击“确定”**。 重新生成解决方案。

  3. 若要设置系统必备组件,请单击 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 版本。

  4. 使用 ClickOnce 部署 C# 应用程序。 右击 CSharpDriver 项目,然后单击**“发布”。 在发布向导中单击“完成”**。 运行生成的 CSharpDriver.application。 注意下列事项:

    • Visual F# 运行时包随应用程序附带。

    • 运行该应用程序时,会安装 F# 运行时包并成功执行该应用程序。

后续步骤

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

请参见

其他资源

Visual F# 演练

示例和演练 (F#)