作为学习练习,我正在使用 F# 和 F# 的类型提供程序功能对 5000 行 csv 文件进行一些数据分析。当我在 f# 中使用类型提供者生成的类型时,csv 文件的标题行自然会成为该类型的字段名称。
type restaurantCsv = CsvProvider<"C:\Users\Paul\Desktop\HealthDepartment\RestaurantRatings2013.csv",HasHeaders=true>
type RawInspectionData(filename : string) =
member this.allData = restaurantCsv.Load(filename)
member public this.inspectionsList = this.allData.Data.ToList()
member this.FilterByName(name : string) =
this.allData.Data
|> Seq.filter (fun x -> x.EstablishmentName.Contains(name))
此外,我从单元测试 C# 文件调用 F# 代码(在上述代码创建的库中)。效果很好。但是当我使用 F# 从
IEnumerable<out T>
返回的 FilterByName
时,字段名称信息不会保留。所以我有代码将新字段名称从元组映射到 .Item1、Item2 等:
var inspectionsOnCafes = inspections2013.FilterByName("Cafe");
var inspections = (from row in inspectionsOnCafes
select new
{
inspectorID = row.Item3,
restaurantName = row.Item5,
inspectionDate = row.Rest.Item6
}).ToList();
我的问题:有没有办法让 C# 识别 F# 生成类型中的字段名称,这样我就不必将 row.Item# 映射到易于阅读的字段名称?
换句话说,有没有办法让我拥有这样的代码:
inspectorID = row.InspectorID,
// etc.
注意:我查看了如何创建可从 C# 使用的 F# 类型提供程序? 但 Cameron Taggert 的问题和 Tomas Petricek 的答案在我看来似乎与类型提供程序的略有不同。即使他们是准确的,我也不明白,所以我仍然需要更多帮助。
在 F# 中,有两种不同类型的类型提供程序。更常见和更简单的是擦除类型提供程序。更复杂的是生成类型提供者。
这种区别对于 C# 来说非常重要,因为:
擦除的类型提供程序只是编译器的魔法。这是一种确保您的代码格式正确、正确使用底层 API 的方法。但这只是编译时,并且不会生成任何类型。相反,底层类型被用作内部表示。这种类型提供程序在 C# 中使用起来不太方便,因为在 C# 中您只能获取底层类型。
生成类型提供程序是编译时真正的代码生成步骤。在这种情况下,会生成类型,因此实际上存在于程序集中,并且可以从 C# 中使用。
erased 类型提供者所期望的问题。而底层类型只是一个元组,但不会生成像类或记录这样的好类型。并且您不能在 C# 中使用 F# 名称,除非类型提供程序的编写方式与生成类型提供程序不同。