Все классы и структуры в F#, даже те, которые мы сами создаем, а также базовые типы, такие как int, являются неявно производными от класса
Object. Даже если мы явно не наследуемся от класса Object, по умолчанию неявно класс Object все равно стоит на вершине
иерархии наследования. Поэтому все типы и классы могут реализовать те методы, которые определены в классе System.Object. Рассмотрим эти методы.
Метод ToString возвращает строковое представление объекта. Для базовых типов просто будет выводиться их строковое значение:
let n: int = 7
printfn $"{n.ToString()}" // 7
let f: float = 3.5
printfn $"{f.ToString()}" // 3.5
Для классов и структур этот метод выводит полное название класса. И мы можем переопределить данный метод. Посмотрим на примере:
type Person(_name) = class
let name = _name
override _.ToString() = name
end
let tom = Person("Tom")
printfn $"{tom}" // Tom
type Clock = struct
val hours: int
val minutes: int
val seconds: int
new(h, m, s) = { hours = h; minutes = m; seconds=s}
override this.ToString() = $"{this.hours}:{this.minutes}:{this.seconds}"
end
let time = Clock(9, 30, 20)
printfn $"{time}" // 9:30:20
Для переопределения метода ToString используется ключевое слово override (как и при обычном переопределении методов). Для класса Person метод ToString возвращает значение поля name. Для структуры Clock метод ToString() возвращает значения полей hours, minutes, seconds, объединенные в одну строку.
И в тех ситуациях, где надо будет преобразовать объект в строку, будет возвращаться результат метода ToString.
Метод GetHashCode позволяет возвратить некоторое числовое значение, которое будет соответствовать данному объекту или его числовой хэш-код. По данному числу, например, можно сравнивать объекты. Можно определять самые разные алгоритмы генерации подобного числа или взять реализацию базового типа:
type Person(_name) = class
member val Name = _name
override this.GetHashCode() = this.Name.GetHashCode()
end
Обычно данный метод реализуется вместе с методом Equals
Метод Equals позволяет сравнить два объекта на равенство:
type Person(_name) = class
member val Name = _name
override this.GetHashCode() = this.Name.GetHashCode()
override this.Equals obj =
if obj :? Person then
let person = obj :?> Person
if this.Name = person.Name then true
else false
else
false
end
Метод Equals принимает в качестве параметра объект любого типа. Поскольку мы хотим сравнивать только с объектами класса Person,
то вначале проверяем, представляет ли объект класс Person. Для этого применяется оператор :? - слева от оператора идет объект, который
надо проверить, а справа - тип. Если объект является объектом этого типа, то оператор возвращает true.
if obj :? Person then
Дальше для упрощения сравниваем объекты по их свойству Name - если оно одинаково, то объекты равны. Но чтобы обратиться к свойству Name объекта obj,
нам надо преобразовать его к типу Person. Для этого применяется оператор :?> - слева от оператора идет объект, который
надо преобразовать, а справа тип, к которому надо преобразовать. Результат преобразования получаем в значение person:
let person = obj :?> Person
Затем сравниваем по именам. Если имена равны, возвращаем true, что будет говорить, что объекты равны. Однако при необходимости реализацию метода можно сделать более сложной, например, сравнивать по нескольким свойствам при их наличии, по каким-то другим аспектам.
Применение метода:
let tom = Person("Tom")
let bob = Person("Bob")
let tomas = Person("Tom")
printfn $"tom = bob: {tom.Equals(bob)}" // tom = bob: false
printfn $"tom = tomas: {tom.Equals(tomas)}" // tom = tomas: true
При этом в данном случае мы могли бы применить операцию сравнению =, результат был бы тот же самый:
let tom = Person("Tom")
let bob = Person("Bob")
let tomas = Person("Tom")
printfn $"tom = bob: {tom = bob}" // tom = bob: false
printfn $"tom = tomas: {tom = tomas}" // tom = tomas: true
Метод GetType позволяет получить тип данного объекта:
type Person(_name) = class
let name = _name
end
let tom = Person("Tom")
printfn $"{tom.GetType()}" // Program+Person
Этот метод возвращает объект типа System.Type, который с помощью своих свойств и методов позволяет нам исследовать объект. Например, проверим, является ли тип классом:
type Person(_name) = class
let name = _name
end
let tom = Person("Tom")
printfn $"IsClass: {tom.GetType().IsClass}" // IsClass: true
В отличие от методов ToString, Equals, GetHashCode метод GetType не переопределяется.