ООП в F# для взаимодействия с .NET
Когда нужен объектный стиль
Внутри F#-проекта домен чаще описывают записями (type Person = { Name: string }) и размеченными объединениями (type Payment = Cash of decimal | Card of string). Это даёт match, исчерпывающие ветки и неизменяемые данные (186).
Классы, интерфейсы и перечисления CLI подключают, когда:
- сборку вызывают из C# или VB;
- нужно наследовать тип из .NET Framework или библиотеки;
- DI-контейнер ASP.NET Core ждёт
IService,IHostedServiceи т.п.; - оборачивают компонент с событиями и
IDisposable(UI, сокеты,HttpClientв старом стиле).
Цель статьи — минимальный набор ООП для interop, без полного курса C#.
Предварительно: F# в экосистеме .NET · Сопоставление с образцом.
Как F# попадает в объектную модель .NET
Любой тип F# компилируется в тип CLR (как C#). Записи и DU — тоже классы с особыми атрибутами. Снаружи solution на C# видит обычные типы с методами и свойствами, если вы их явно экспортируете (public, member).
Термины:
| Термин | Смысл |
|---|---|
| CLR | Среда выполнения .NET |
| member | Метод или свойство типа, видимое снаружи |
Конструктор () | Создание экземпляра класса |
| Interop | Совместная работа F# и других .NET-языков в одном solution |
Класс с состоянием
type Counter() =
let mutable value = 0
member _.Increment() = value <- value + 1
member _.Current = value
Разбор:
type Counter() =— класс с параметрless-конструктором().let mutable value = 0в теле класса — приватное поле экземпляра (снаружи недоступно).member _.Increment()— метод;_вместо имениthis(можно писатьthis, если нужно).member _.Current— свойство только для чтения (вычисляется при каждом обращении).
Использование:
let c = Counter()
c.Increment()
printfn "%d" c.Current // 1
Из C#:
var c = new Counter();
c.Increment();
Console.WriteLine(c.Current);
Имена и сигнатуры совпадают с правилами .NET.
Свойства и параметры конструктора
type Person(name: string, age: int) =
member val Name = name with get, set
member val Age = age with get, set
nameиage— параметры конструктора, доступны в теле класса.member val ... with get, set— автосвойство: компилятор создаёт поле и аксессоры.
Для DTO, которые сериализуют в JSON, часто достаточно записи с [<CLIMutable>] — проще и привычнее для REST API (Справочник).
Структуры (struct)
[<Struct>]
type Point =
struct
val X: float
val Y: float
new(x, y) = { X = x; Y = y }
end
Структура в .NET — тип значения: копируется при присваивании, может уменьшить давление на сборщик мусора в горячих циклах. Записи F# по умолчанию — ссылочные типы; для мелких неизменяемых значений иногда ставят [<Struct>] на record (зависит от версии языка и сценария).
| Выбор | Когда |
|---|---|
| Record / DU | домен, match, неизменяемость |
class | наследование, изменяемое состояние, события |
struct | малые значения, производительность |
Интерфейсы
type IRepository =
abstract member Get: int -> string option
type InMemoryRepository() =
interface IRepository with
member _.Get id =
if id = 1 then Some "alpha" else None
- В интерфейсе методы объявляют через
abstract member. - Реализация — блок
interface IRepository with ...внутри класса. - Несколько интерфейсов — несколько блоков
interface ... with.
C#-код может принять IRepository и не знать, что реализация написана на F#.
Явная реализация интерфейса (как в C# «скрыть метод от публичного API») поддерживается, если нужно развести имена.
Наследование
type Animal() =
abstract member Speak: unit -> string
default _.Speak() = "..."
type Dog() =
inherit Animal()
override _.Speak() = "woof"
| Ключевое слово | Роль |
|---|---|
abstract member | Контракт для наследников |
default | Реализация по умолчанию в базовом типе |
inherit Animal() | Вызов конструктора базового класса |
override | Замена реализации в наследнике |
Глубокие иерархии в F# редки; композиция функций и DU обычно короче и безопаснее для match.
Перечисление CLI и DU
Enum для контракта, совместимого с C#:
type Status =
| Draft = 0
| Published = 1
| Archived = 2
Числовые значения фиксируют совместимость с enum в C#.
DU — когда у каждого случая свои данные:
type DocumentState =
| Draft of title: string
| Published of publishedAt: System.DateTime
Обработка — через match (186). Enum — когда внешний API уже зафиксировал набор констант без полезной нагрузки.
Статические члены и модули
type MathConstants =
static member Pi = 3.14159265
static member CircleArea r = MathConstants.Pi * r * r
Аналог static в C#. Набор чистых функций без состояния часто оформляют модулем верхнего уровня:
module Geometry =
let circleArea r = System.Math.PI * r * r
Модуль не требует new — удобнее для F#-клиентов; класс со static — когда так ожидает C#.
obj и переопределение Object
Все типы наследуют System.Object (obj в F#). Для классов можно переопределить ToString(), Equals(), GetHashCode(). Записи и DU получают разумные реализации от компилятора. При вызове API, ожидающего obj, приведение обычно не требуется.
Рекомендации для общих solution
| Ситуация | Подход |
|---|---|
| Публичный API библиотеки для C# | Понятные имена типов, [<CLIMutable>] на DTO, [<RequireQualifiedAccess>] на модулях при конфликтах имён |
| Скрыть детали | private DU внутри, наружу — интерфейс или функции модуля |
| WPF / WinForms | Классы с событиями допустимы; бизнес-логику — в чистых функциях |
| ASP.NET Core | Тонкие классы-обработчики + функциональное ядро в F# library |
Пример границы: в App.Core (F#) — type Order = ... и функции validate, price; в App.Web (C#) — Controller, вызывающий OrderService из DLL.
Дальше
- Асинхронность: task, async и агенты
- Структура F#-проекта
- Справочник по F# — атрибуты interop (
CLIMutable,CompilationRepresentation) - Первая программа на F#
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Платформа .NET - архитектура экосистемы, инструменты разработки и модель выполнения приложений. Эти механизмы позволили реализовать фундаментальный принцип .NET — язык — это синтаксический фасад над общей семантикой CLR. Понимание архитектуры .NET невозможно без хронологического контекста, поскольку многие текущие решения — это результат многолетней итеративной оптимизации. Типы приложений на платформе .NET - веб, desktop, мобильные и облачные сценарии в единой экосистеме. Сборка и развёртывание .NET-приложений - артефакты, среды выполнения и практики доставки в продакшен. Пакеты и зависимости в .NET - управление версиями, восстановление пакетов и интеграция в процесс сборки. В Visual Studio проект — это единица сборки — он определяет, что и как компилируется. Проект содержит .csproj, исходные файлы, ресурсы и метаданные зависимостей. NuGet - система управления пакетами .NET для публикации, версионирования и подключения зависимостей. ADO.NET в .NET 8+ — Connection, Command, параметры и провайдеры; краткая история классического ADO (COM). ASP.NET - веб-платформа Microsoft для разработки серверных приложений, API и динамических сайтов. Экосистема .NET-приложений - поддерживаемые платформы, сценарии разработки и интеграция с современными устройствами. F# в экосистеме .NET - функциональный стиль, совместимость с платформой и применение в прикладной разработке.Платформа .NET
История платформы .NET
Архитектурные особенности .NET
Типы приложений на платформе .NET
Сборка и развёртывание .NET-приложений
Пакеты и зависимости в .NET
Инструменты разработки для .NET
NuGet - система управления пакетами
ADO.NET - доступ к данным
ASP.NET - веб-платформа Microsoft
Экосистема .NET-приложений
F# - функциональный язык в экосистеме .NET