inline
- это особенность, уникальная для компилятора F #, которую C # не поддерживает.Вам нужно будет определить (по крайней мере) операторы для int32
и double
явно.
inline
функции будут встроены компилятором F #, заменив универсальный параметр (и) на compile-Время известных типов.Общая функция - это , в общем не вызывается во время выполнения.Несколько исключений, когда реализация выполняет динамическую диспетчеризацию (см., Например, AdditionDynamic ) do работает во время выполнения, но медленнее, чем их inline
d эквиваленты.Другое исключение - неуниверсальные функции inline
, где метаданные inline
просто игнорируются компилятором C #.
inline
заразна, все функции, вызывающие функции inline
, сами должны быть inline
вверх по дереву вызовов, где все параметры типа для вызываемого абонента известны во время компиляции .Это объясняет ошибку ... would escape its scope
.Следовательно, если inline
заканчивается на границах сборки, эти функции не могут использоваться в проектах, отличных от F #.
Обновление : Вы правы, отмечая оператор inline
без фактического использованияSRTP ( Статически разрешенные параметры типа ) не имеют никакого эффекта: тип T
не имеет ограничений, поэтому его не нужно знать во время компиляции:
let inline Add(p1: Nothing<'T>, p2: Nothing<'T>) = Nothing<_>(p1.X)
имеет подпись
val inline Add : p1:Nothing<'T> * p2:Nothing<'T> -> Nothing<'T>
как только вы фактически используете функцию inline
(здесь для возможности использования +
), T
, как известно, имеет некоторые ограничения:
let inline Add(p1: Nothing<_>, p2: Nothing<_>) = p1.X + p2.X
имеет подпись
val inline Add :
p1:Nothing< ^a> * p2:Nothing< ^b> -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
С точки зрения C #:
// normal (runtime) generics: works
let inline Add(p1: Nothing<'T>, p2: Nothing<'T>) = Nothing<_>(p1.X)
// SRTPs decalred only: works
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X)
// SRTPs (requires member (+)), needs type annotation, slow (using AdditionDynamic, that is reflection), may fail at runtime (if no + operator)
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X + p2.X)
// needs type annotation, guaranteed failure at runtime (no dynamic polyfill)
let inline Add(p1: Nothing<(^T)>, p2: Nothing<(^T)>) = Nothing<_>(p1.X %% p2.X)
Теперь, если мы используем одну из этих функций в качестве операторов, толькоnon-SRTP будет работать:
static member inline (*) (p1: Nothing<'T>, p2: Nothing<'T>) : Nothing<'T> = Nothing(p1.X) // fine
с объявлением SRTP уже достаточно:
static member inline (+) (p1: Nothing<(^a)>, p2: Nothing<(^a)>) : Nothing<(^a)> = Nothing(p1.X) // can not be used fom C#
Почему это так? C # вообще не поддерживает универсальные операторы (в dotnet / csharplang есть несколько запросов), тогда как в F # они могут быть inline
d.И действительно, если мы посмотрим на декомпилированные источники:
// introduces new generic parameter `a`
public static Nothing<a> operator +(Nothing<a> p1, Nothing<a> p2)
// uses T from containing struct
public static Nothing<T> operator *(Nothing<T> p1, Nothing<T> p2)
Независимо от того, наложено ли ограничение 'T when 'T: (static member (+): 'T * 'T -> 'T)
на структуру или оператор не имеет значения: мы всегда получим универсальный оператор .