Как переопределить GetHashCode и CompareTo для дискриминируемого объединения в F#?
У меня есть простой F# дискриминируемый союз, который комбинирует bool, string и float. Я хочу переопределить Object.Equals(arg) этого объединения, чтобы я мог добавить эпсилон для учета ошибок точности при проверке на равенство с плавающей точкой. Компилятор жаловался на то, что если я переопределю this.Equals(arg), я должен также переопределить this.GetHashCode() и this.CompareTo(arg). Для их переопределения у меня не запланировано никаких специальных функций, поэтому я просто хотел бы вызвать версии этих методов по умолчанию. В моей реализации теперь у меня есть три вызова GetHashCode и три вызова CompareTo для каждого типа в моем различаемом объединении: по одному для каждого типа.
Есть ли способ кодировать переопределение GetHashCode с помощью всего одного вызова GetHashCode? Тот же вопрос для CompareTo? Все типы в моем различаемом союзе реализуют ICompareable.
[<CustomEquality;CustomComparison>]
type MyType =
| Bool of bool
| Str of string
| Float of float
override this.Equals(arg) =
let epsilon = 0.1
match arg with
| :? MyType as other ->
match this, other with
| Bool(a), Bool(b) -> a = b
| Str(a), Str(b) -> a = b
| Float(a), Float(b) -> Math.Abs(a - b) < epsilon
| _ -> false
| _ -> false
override this.GetHashCode() =
match this with
// Three calls to GetHashCode. I'd like only one
| Bool(a) -> a.GetHashCode()
| Str(a) -> a.GetHashCode()
| Float(a) -> a.GetHashCode()
| _ -> 0
interface System.IComparable with
member this.CompareTo arg =
match arg with
| :? MyType as other ->
match this, other with
// Three calls to CompareTo. I'd like only one
| Bool(a), Bool(b) -> a.CompareTo(b)
| Str(a), Str(b) -> a.CompareTo(b)
| Float(a), Float(b) -> a.CompareTo(b)
| _ -> 0
| _ -> 0
1 ответ
Вы можете определить вспомогательное свойство, которое извлекает содержимое DU как obj
:
member this.Value =
match this with
| Bool(b) -> box b
| Str(s) -> box s
| Float(f) -> box f
Тогда вы можете реализовать GetHashCode
просто получая значение (которое включает в себя некоторый бокс, так что это будет немного медленнее) и вызывая GetHashCode
на возвращаемом объекте:
override this.GetHashCode() =
this.Value.GetHashCode()