我需要描述以下关系:
type FieldDef<'Object, 'Val> {
Name: string;
Resolve: 'Object -> 'Val
}
type ObjectDef<'Object> {
Name: string;
Fields: FieldDef<'Object, _> list
}
// example usage
type MyRecord = { X: int; Y: string; }
let myRecordDef = {
Name = "MyRecord"
Fields = [
{ Name = "x"; Resolve: fun r -> r.X }
{ Name = "y"; Resolve: fun r -> r.Y }
]
}
不幸的是,_
在此用例中无效。在这种情况下,FieldDef
的第二种类型参数可能会有所不同 - 在C#中,我们可以将其注释为逆变并绑定到类型Object
。如何在不失去太多类型安全的情况下在F#中实现类似的结果?
答案 0 :(得分:2)
正如约翰所说,如果你想要完全通用,那么你就会失去类型安全性。那么你的ObjectDef类是
type ObjectDef<'Object> =
{
Name: string;
Fields: FieldDef<'Object, obj> list
}
我不知道&#34;如何通用&#34;你需要。这里提供了一个建议,您至少使用一些明确表示的字段类型:首先定义一个有区别的联合,替换完全通用的'Object -> 'Val
:
type FieldGetter<'T> =
| Int of ('T -> int)
| String of ('T -> string)
| AnythingElse of ('T -> obj)
然后定义一个新的字段定义记录,以及一些方便的重载:
type FieldDef2<'Object> =
{
Name: string;
Resolve: FieldGetter<'Object>
}
static member Create(name, f) = { Name = name; Resolve = Int f }
static member Create(name, f) = { Name = name; Resolve = String f }
static member Create(name, f) = { Name = name; Resolve = AnythingElse f }
type ObjectDef2<'Object> =
{
Name: string;
Fields: FieldDef2<'Object> list
}
然后你的例子变成:
let myRecordDef = {
Name = "MyRecord"
Fields = [ FieldDef2<_>.Create("x", fun r -> r.X);
FieldDef2<_>.Create("y", fun r -> r.Y) ]
}