我需要比较不同类型的对象,我知道它们都有属性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
Run Code Online (Sandbox Code Playgroud)
此外,我还有类型的比较器类型的实例化.所以,理论上编译器有足够的信息.
但是它给出了一个错误:"基于此程序点之前的信息查找不确定类型的对象.在此程序点之前可能需要类型注释来约束对象的类型.这可以允许解析查找. "
我想知道为什么F#在这里失败了?是否有任何实际/理论限制或者它没有实施?这种推断可能非常有用.
我怀疑解释是关于F#编译器只是向前走.C#的限制没有.这是错误消息抱怨的内容.是这样吗?
成员约束不能用于类型,这就是你不能这样做的原因.看到这里.
你可以做的是创建一个比较器类,它接受特定类型的显式相等检查和哈希码生成函数,例如
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
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用内联函数为与您要强加的约束匹配的类型生成上述实例:
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 >
Run Code Online (Sandbox Code Playgroud)
假设您有一些TestType具有两个必需属性的类型:
type TestType =
member this.Legacy_id = 7
member this.Id = 9
Run Code Online (Sandbox Code Playgroud)
例如,您可以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 }
Run Code Online (Sandbox Code Playgroud)
类型推断是关于推断一个类型,而不是证明了一些通用的类型参数满足任意条件的所有实例(见名义与结构类型系统).SO上的静态解析类型参数有很多好的答案.
| 归档时间: |
|
| 查看次数: |
106 次 |
| 最近记录: |