为什么类型推断不自动确定类型上存在 属性?
Why doesn't type inference determine automatically that property exists on type?
我需要比较不同类型的对象,我知道它们都具有属性 Id 和 Legacy_id。不幸的是,我无法为它们添加接口,因为类型来自数据库模式。我希望以下比较器能够工作:
type Comparer<'T >()=
interface System.Collections.Generic.IEqualityComparer<'T> with
member this.Equals (o1:'T,o2:'T)=
o1.Legacy_id=o2.Legacy_id
member this.GetHashCode(o:'T)=
o.Id+o.Legacy_id
我还有比较器类型的实例化。所以,理论上编译器有足够的信息。
但是报错:"Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
我想知道为什么 F# 在这里失败了?是否有任何 real/theoretical 限制或只是没有实施?这种推论可能非常有用。
我怀疑关于 F# 编译器只是向前走的解释。 C# 没有的限制。这就是错误消息所抱怨的。是这样吗?
成员约束不能用于类型,这就是您不能这样做的原因。参见 here。
你可以做的是创建一个比较器 class,它接受特定类型的显式相等性检查和哈希码生成函数,例如
type Comparer<'T>(equalityFunc, hashFunc) =
interface System.Collections.Generic.IEqualityComparer<'T> with
member this.Equals (o1:'T,o2:'T)=
equalityFunc o1 o2
member this.GetHashCode(o:'T)=
hashFunc o
然后您可以使用内联函数为符合您希望施加的约束的类型生成上述实例:
let inline id obj =
( ^T : (member Id : int) (obj))
let inline legacyId obj =
( ^T : (member Legacy_id : int) (obj))
let inline equals o1 o2 =
id o1 = id o2
let inline hash o =
id o + legacyId o
let inline createComparer< ^T when ^T : (member Id: int) and ^T : (member Legacy_id : int) >() =
Comparer< ^T >(equals, hash) :> System.Collections.Generic.IEqualityComparer< ^T >
假设您有某种类型 TestType
,它具有两个必需的属性:
type TestType =
member this.Legacy_id = 7
member this.Id = 9
然后您可以执行 createComparer<TestType>()
生成适合您的类型的相等比较器。
获取比较器的简洁方法,例如创建 HashSet
是:
let inline getId o = (^T : (member Id : int) o)
let inline getLegacyId o = (^T : (member Legacy_id : int) o)
let inline legacyComparer< ^T when ^T : (member Id : int) and ^T : (member Legacy_id : int)>() =
{ new System.Collections.Generic.IEqualityComparer<'T> with
member __.GetHashCode o = getId o + getLegacyId o
member __.Equals(o1, o2) = getLegacyId o1 = getLegacyId o2 }
类型推断是关于推断 a 类型,而不是证明某些泛型类型参数满足所有实例化的任意条件(参见标称类型系统与结构类型系统)。 SO 上已经有很多关于静态解析类型参数的好答案。
我需要比较不同类型的对象,我知道它们都具有属性 Id 和 Legacy_id。不幸的是,我无法为它们添加接口,因为类型来自数据库模式。我希望以下比较器能够工作:
type Comparer<'T >()=
interface System.Collections.Generic.IEqualityComparer<'T> with
member this.Equals (o1:'T,o2:'T)=
o1.Legacy_id=o2.Legacy_id
member this.GetHashCode(o:'T)=
o.Id+o.Legacy_id
我还有比较器类型的实例化。所以,理论上编译器有足够的信息。
但是报错:"Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
我想知道为什么 F# 在这里失败了?是否有任何 real/theoretical 限制或只是没有实施?这种推论可能非常有用。
我怀疑关于 F# 编译器只是向前走的解释。 C# 没有的限制。这就是错误消息所抱怨的。是这样吗?
成员约束不能用于类型,这就是您不能这样做的原因。参见 here。
你可以做的是创建一个比较器 class,它接受特定类型的显式相等性检查和哈希码生成函数,例如
type Comparer<'T>(equalityFunc, hashFunc) =
interface System.Collections.Generic.IEqualityComparer<'T> with
member this.Equals (o1:'T,o2:'T)=
equalityFunc o1 o2
member this.GetHashCode(o:'T)=
hashFunc o
然后您可以使用内联函数为符合您希望施加的约束的类型生成上述实例:
let inline id obj =
( ^T : (member Id : int) (obj))
let inline legacyId obj =
( ^T : (member Legacy_id : int) (obj))
let inline equals o1 o2 =
id o1 = id o2
let inline hash o =
id o + legacyId o
let inline createComparer< ^T when ^T : (member Id: int) and ^T : (member Legacy_id : int) >() =
Comparer< ^T >(equals, hash) :> System.Collections.Generic.IEqualityComparer< ^T >
假设您有某种类型 TestType
,它具有两个必需的属性:
type TestType =
member this.Legacy_id = 7
member this.Id = 9
然后您可以执行 createComparer<TestType>()
生成适合您的类型的相等比较器。
获取比较器的简洁方法,例如创建 HashSet
是:
let inline getId o = (^T : (member Id : int) o)
let inline getLegacyId o = (^T : (member Legacy_id : int) o)
let inline legacyComparer< ^T when ^T : (member Id : int) and ^T : (member Legacy_id : int)>() =
{ new System.Collections.Generic.IEqualityComparer<'T> with
member __.GetHashCode o = getId o + getLegacyId o
member __.Equals(o1, o2) = getLegacyId o1 = getLegacyId o2 }
类型推断是关于推断 a 类型,而不是证明某些泛型类型参数满足所有实例化的任意条件(参见标称类型系统与结构类型系统)。 SO 上已经有很多关于静态解析类型参数的好答案。