将c#logic转换为f#的最佳实践

时间:2017-10-25 10:38:23

标签: f# f#-interactive c#-to-f# f#-data

所以我把它作为一个剧本:

#r @"..\packages\FSharp.Data.2.4.2\lib\net45\FSharp.Data.dll"
#r "System.Xml.Linq.dll"

open FSharp.Data

// provide some URL, file path, or raw JSON sample
// that can be used at compile time to generate types
type Json = JsonProvider<"example.json">

// at runtime, load up new sample matching that schema
let response = Http.Request("https://world.openfoodfacts.org/api/v0/product/737628064502.json")
let samples = Json.Parse(response.Body.ToString())

我想做的是:

  • 创建扩展程序,其参数类型为: Models.Product ,名为 MyProduct ,可从名为<的dll获取EM> Models.dll
  • 向扩展程序添加2个额外参数
    • 字符串语言
    • 字符串条形码
  • 根据收到的json文件更新 MyProduct.Title
  • 使用更新的数据
  • 返回 MyProduct

在c#中会是这样的:

public static Models.Product UpdateFromRemote(this Models.Product Product, string Language, string Barcode)
{
    //the f# code included above to fetch the remote source
    //only the url is fetched from:
    //  string.Format("https://{0}.openfoodfacts.org/api/v0/product/{1}.json",Language,Barcode);  

    Product.Title =  samples.Product.GenericName; //samples is the fetched resource from the f# code

    return Product;
}

f#中的逻辑是什么?

目前我有这个(这还不正确/完整)

namespace LookupByBarcode.openfoodfacts.fSharp

open FSharp.Data

type model(Language,Barcode) = 
    member this.Language = Language
    member this.Barcode = Barcode

module getRemote = 
    type json = JsonProvider<"example.json">
        let response = json.Load("https://world.openfoodfacts.org/api/v0/product/737628064502.json")
            let Title = response.Product.ProductNameEn

1 个答案:

答案 0 :(得分:3)

如果您有一个无法修改的外部DLL定义了类型Product,那么就没有简单的方法可以向产品添加新字段。我认为最优雅的F#方式是将其包装在添加附加信息的记录中:

type MyProduct = 
  { Product : Product
    Language : string
    Barcode : string }

接下来,如果要更新MyProduct值以使其反映新获得的标题,则它取决于基础Product类型的外观。它是可变的还是不可变的?

要获得惯用的F#代码,您需要创建一个返回克隆的函数。这对于F#记录很容易,但对于C#对象可能很难。它可能看起来像这样:

let updateProduct newTitle newLanguage myproduct =
  // Create a new `Product` with changed title. If you want to avoid mutation,
  // you need to create a new instance, which might be tedious for C# objects
  let op = myproduct.Product
  let np = 
    Product
      (Title = newTitle, OtherThing = op.OtherThing,
       YetAnotherThing = op.YetAnotherThing)

  // Now create a new updated F# record - this is much easier
  { myprodcut with Product = np; Language = newLanguage }

使用F#中的C#可变对象惯用工作会很棘手,所以我的建议是在F#中定义域模型,这样你就可以在任何地方使用漂亮的F#with关键字。也就是说,改变C#对象也是有意义的 - 如果这是你真正想做的事情。