【发布时间】:2017-02-22 13:52:27
【问题描述】:
我需要比较不同类型的对象,我知道它们都具有属性 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
我也有比较器类型的实例化类型。所以,理论上编译器有足够的信息。
但它给出了一个错误:“基于此程序点之前的信息查找不确定类型的对象。在此程序点之前可能需要类型注释来限制对象的类型。这可能允许查找解决。”
我想知道为什么 F# 在这里失败了?是否有任何实际/理论上的限制,或者只是没有实施?这种推断可能非常有用。
我怀疑有关 F# 编译器的解释只是向前走。 C# 没有限制。这就是错误消息所抱怨的。是这样吗?
【问题讨论】:
-
这不能被编译,因为任何给定的
'T不保证有一个名为Id的属性。这是一个思想实验:如果你将这个类实例化为Comparer<int>,会发生什么? -
@FyodorSoikin 但我没有将它实例化为 Comparer
。所以,在我用正确的类型实例化它之前,编译可以工作。 -
这在 C# 中也不起作用,因为
'T没有Id属性。 C#/F# 泛型只进行一次类型检查,并且不会像 C++ 模板那样根据它们的用途进行扩展。 -
F# 类型推断功能强大,但并不完美。它不能做的一件事是推断“伪接口”,例如“所有这些类都有一个 Id 属性”。这部分是因为它与.Net 类型系统相关联,该系统不允许此类伪接口。而且,F# 编译器希望保证安全。并且仅仅因为你不实例化
Comparer<int>现在,并不意味着编译器可以知道你在未来不会这样做。由于它不能保证这一点,它不能假设'T将始终具有Id属性。 -
我想我找到了答案。这似乎是可能的。它是关于鸭子类型和编译时多态性的。在我尝试将其应用于我的案例时,请稍候。 stackoverflow.com/questions/7065939/f-and-duck-typing
标签: f# type-inference