Я думаю, что, как вы написали, это, вероятно, лучший вариант.
Если вы не хотите заниматься боксом, то перегруженная функция write
определенно необходима, потому что сериализация должна быть реализована по-разному для разных типов.Использование члена inline
также не работает в этом случае, потому что функция inline
может требовать только определенный экземпляр или статический метод для какого-либо значения, которое она получает, но не определенной перегрузки.
Разумное решение, которое позволяет избежать некоторого дублирования, состоит в том, чтобы определить только одну перегруженную функцию (т.е. write
) и затем передать ее явно в качестве аргумента другим функциям, если они в этом нуждаются.Вы могли бы написать что-то вроде:
type Stream (capacity) =
let data = Array.zeroCreate capacity
member private s.position = ref 0
static member private encoder = new Text.UTF8Encoding()
static member Write (x, o, a : byte[]) =
for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256)
static member Write (x, o, a : byte[]) =
for i = 0 to 1 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256s)
static member Write (x : string, o : int, a : byte[]) =
Stream.encoder.GetBytes(x, 0, x.Length, a, o) |> ignore
// Format takes a writer function 'f' as the first argument
static member Format (x, s) f = let a = Array.create s 0uy in f(x, 0, a); a
// When you call 'Format' with 'Stream.Write' as an argument,
// the compiler chooses the right overload for you
Stream.Format (1s, 100) Stream.Write
Stream.Format ("foo", 100) Stream.Write
Это позволяет избежать некоторого дублирования кода на стороне определения, но увеличивает продолжительность использования.Если вам не нужно много функций, таких как Format
, то лучшим способом может быть определение перегрузки с некоторым дублированием кода, как вы делали изначально.
Относительно inline
, вы можете использовать это, чтобы указать, чтотип аргумента должен реализовывать некоторый конкретный элемент (экземпляр или статический), но вы не можете сказать, что должна быть определенная перегрузка.Если вы написали оболочки для всех трех типов (int16
, string
, ...), которые имеют статический член Write
, вы можете написать:
let inline format< ^T when ^T :
(static member Write : ^T * int * byte[] -> unit)> (value:^T) size =
let a = Array.create size 0uy
(^T : (static member Write : ^T * int * byte[] -> unit) (value, 0, a))
a
... но это дажеболее сложное решение, которое также требует написания дополнительного кода при вызове format
, поэтому я бы не стал использовать этот подход (но может быть полезно знать, что он существует).