F# 提供的类型上的模式匹配
首先,获取一个模式并解析:F# 提供的类型上的模式匹配,f#,type-providers,f#-data,F#,Type Providers,F# Data,首先,获取一个模式并解析: type desc=JsonProvider 让json=“”[{“name”:“Kitten”,“age”:322}]“” 让typedJson=desc.Parse(json) 现在我们可以访问typedJson。[0].Age和.Name属性,但是,我希望在编译时对它们进行模式匹配,以便在模式更改时获得错误 由于这些属性已被擦除,我们无法在运行时获取它们: let``返回false```()= typedJson[0]。GetType() .FindMembe
type desc=JsonProvider<“”“[{”name:““age”:1}]”,InferTypesFromValues=true>
让json=“”[{“name”:“Kitten”,“age”:322}]“”
让typedJson=desc.Parse(json)
现在我们可以访问typedJson。[0]
.Age和.Name属性,但是,我希望在编译时对它们进行模式匹配,以便在模式更改时获得错误
由于这些属性已被擦除,我们无法在运行时获取它们:
let``返回false```()=
typedJson[0]。GetType()
.FindMembers(MemberTypes.All、BindingFlags.Public | | | BindingFlags.Instance、,
MemberFilter(趣味->真),空)
|>Array.exists(fun m->m.ToString().Contains(“Age”))
…我已使用活动模式创建了运行时检查版本:
let(| Name | Age |)k=
设toID=NameUtils.uniqueGenerator NameUtils.nicePascalName
设idk=toidk
将idk与
|_uk.等于(“年龄”)时->年龄
|_uk.等于时(“名称”)->Name
|ex\u val->failwith(sprintf“\%s\”甚至不应该编译!(ex\u val)
typedJson[0].JsonValue.Properties()
|>Array.map(乐趣(k,v)->
匹配
|年龄->v.AsInteger().ToString()/。。。
|名称->v.AsString())/。。。
|>Array.iter(printfn“%A”)
理论上,如果FSharp.Data
不是操作系统,我就无法实现toID
。总的来说,整个方法似乎是错误的,需要重做工作
我知道不能使用类型提供程序生成有区别的联合,但也许有更好的方法在编译时执行所有这些检查?如果使用
InferTypesFromValues=false
,您将返回一个强类型:
type desc = JsonProvider< """[{"name": "", "age": 1}]""", InferTypesFromValues=false >
这些活动模式可以这样使用:
let json = """[{"name": "Kitten", "age": 322}]"""
let typedJson = desc.Parse(json)
match typedJson.[0] with
| Name "Kitten" n -> printfn "Name is %s" n
| Age 322m a -> printfn "Age is %M" a
| _ -> printfn "Nothing matched"
给定这里的
typedJson
值,匹配项将打印出“Name is Kitten”。据我所知,使用给定的TP无法在编译时找出“Json模式是否已更改”
这就是为什么:
JsonProvider
正是在编译时启动的,它提供了一种在运行时操作Json内容的类型。提供的已擦除类型具有两种运行时静态方法,这两种方法对于任何sample
和typeRoot
使用少量实例属性扩展IJsonDocument
,包括基于编译时提供的示例的属性(在您的示例中为-propertiesName
和Age
)
JsonProvider
后面的Json“schema”——提供的类型,没有其他这样的实体可以在编译时进行比较以进行更改;
desc
及其静态方法,以及其Root
类型及其相应的实例方法
您可以随时处理任意Json内容。所有这些爵士乐在音乐方面几乎都是不可知论的
“Json模式”,在您给定的情况下,只要运行时Json内容代表一个数组,它的元素可能几乎是任意的。
比如说,
type desc = JsonProvider<"""[{"name": "", "age": 1}]"""> // @ compile-time
let ``kinda "typed" json`` = desc.Parse("""[]""") // @ run-time
let ``another kinda "typed" json`` =
desc.Parse("""[{"contents":"whatever", "text":"blah-blah-blah"},[{"extra":42}]]""")
type desc=JsonProvider/@编译时
让“`kinda”键入“json`=desc.Parse(“[]”)/@run-time
让“另一种”类型的“json”=
desc.Parse(“[{”contents:“whatever”,“text:“blah blah blah”},[{“extra”:42}]]”)
两者在运行时都会被愉快地解析为“类型化Json”,符合TP从给定的示例
派生的“模式”,尽管显然名称
和年龄
缺失,如果被访问,将引发异常。
JsonProvider
TP fromFsharp.Data
缺少这样的Json模式处理能力,因此负载验证只能在运行时完成。引用您的评论,其中更好地解释了您试图实现的目标:
谢谢大家!!但我要做的是得到一个编译器错误 如果我在json模式中添加一个新字段,例如颜色,然后忽略它 而后期处理。如果是工会,则为即时FS0025 以及:
是的,我必须处理所有字段,所以我不能依赖于。我希望如此 当模式更改时,如果不添加 必要的处理功能(而不仅仅是忽略新字段或 运行时崩溃) 最简单的解决方案是构造一个“测试”对象 提供的类型带有两个构造函数:一个接受一个JSonValue并对其进行解析-实际上与
JSonValue.Parse
-相同,而另一个需要填写每个字段
这才是我们感兴趣的
我们还将使用命名参数调用它,这样我们不仅在添加或删除字段时安全,而且在重命名或更改字段时也安全
type desc = JsonProvider< """[{"name": "SomeName", "age": 1}]""", InferTypesFromValues=true >
let TestObjectPleaseIgnore = new desc.Root (name = "Kitten", age = 322)
// compiles
显然,该错误引用的是1参数构造函数,因为它试图拟合该构造函数,但您会看到,现在提供的类型有一个3参数构造函数取代了2参数构造函数。
<tldr>
Build some parser to handle your issues. http://www.quanttec.com/fparsec/
</tldr>
构建一些解析器来处理您的问题。http://www.quanttec.com/fparsec/
所以
你想要的东西可以读一些东西并用它做一些事情。不知道这些东西是什么
祝你好运
您不希望类型提供程序为您执行此操作。类型提供程序的全部目的是“在公司”
type desc = JsonProvider< """[{"name": "SomeName", "age": 1, "color" : "Red"}]""", InferTypesFromValues=true >
let TestObjectPleaseIgnore = new desc.Root (name = "Kitten", age = 322)
// compilation error: The member or object constructor 'Root' taking 1 arguments are not accessible from this code location. All accessible versions of method 'Root' take 1 arguments.
<tldr>
Build some parser to handle your issues. http://www.quanttec.com/fparsec/
</tldr>