Веб-версияОткрыть в Telegram

ПостДень 2798. #Оффтоп

28 сентября 2026
.
.NET Разработчик
День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время назад я выложил пост от Steven Giesel о реализации утиной типизации в C# с помощью перехватчиков (interceptors). Тогда это был лишь прототип с множеством недоработок. Теперь же это полноценная библиотека: IfItQuacks. TL;DR Объявите интерфейс, пометьте метод атрибутом [DuckTyped] и передавайте в него любой подходящий объект — без базового класса, без явной реализации интерфейса и без каких-либо атрибутов на самих типах: using IfItQuacks; public interface INamed { string Name { get; } } public class Person { public string Name => "Steven"; } public class Mallard { public string Name => "Donald"; } public partial class Greeter { [DuckTyped] public string Greet( INamed first, INamed second, string greeting = "Hello") => $"{greeting}, {first.Name} and {second.Name}!"; } Console.WriteLine(new Greeter() .Greet(new Person(), new Mallard())); // Hello, Steven and Donald! Ни Person, ни Mallard не знают об INamed. Генератор кода на этапе компиляции проверяет наличие у обоих типов свойства Name и перенаправляет вызов через небольшой сгенерированный адаптер. Никакой рефлексии, никакого dynamic. Если типы несовместимы, анализатор выдаст ошибку. Можно также явно привести объекты к интерфейсу, чтобы хранить их: List<INamed> names = [ Duck.As<INamed>(new Person()), Duck.As<INamed>(new Mallard()) ]; Подробности можно найти в документации. Далее кратко основные моменты. Анонимные типы — это «утки» Анонимные типы отлично «крякают» (по сути, то же самое, что предлагает TypeScript): new Greeter().Greet( new { Name = "Steven" }, new { Name = "Donald" }); По сути, можно писать свои тесты с «мгновенными моками»: public interface IPerson { string Name { get; } int Age { get; } } public partial class AgeChecker { [DuckTyped] public bool IsAdult(IPerson person) => person.Age >= 18; } [Test] public void Should_detect_adults() { var checker = new AgeChecker(); Assert.That( checker.IsAdult(new { Name = "Steven", Age = 90 }), Is.True); Assert.That( checker.IsAdult(new { Name = "Baby Duck", Age = 1 }), Is.False); } Либо: IPerson stub = Duck.As<IPerson>(new { Name = "Donald", Age = 90 }); List<IPerson> family = [ Duck.As<IPerson>(new { Name = "Huey", Age = 10 }), Duck.As<IPerson>(new { Name = "Dewey", Age = 10 }), Duck.As<IPerson>(new { Name = "Louie", Age = 10 }), ]; Идентичность сохраняется Адаптеры перенаправляют вызовы методов Equals, GetHashCode и ToString к обёрнутому экземпляру, благодаря чему они корректно работают в словарях и множествах. Кроме того, можно получить доступ к исходному объекту: var person = new Person(); Duck.As<INamed>(person) .Equals(Duck.As<INamed>(person)); // true Duck .Unwrap(Duck.As<INamed>(person)) is Person; // true А также поддерживаются: - Любой интерфейс, включая интерфейсы фреймворков: Duck.As<IDisposable>(x), параметры IEnumerable<T> и т.п.; - Параметры интерфейса, не требующие утиной типизации (например, ILogger), продолжают принимать реализации, значения null и значения по умолчанию; - Обобщённые интерфейсы (IContainer<T>) и обобщённые методы [DuckTyped] с выведением аргументов типа; - События, индексаторы и реализация интерфейса по умолчанию; - Делегаты, лямбда-выражения и группы методов для интерфейсов с одним методом; - Статические абстрактные члены и операторы с помощью ограничений утиной типизации (where T : IAddable<T>) - включая обобщённую математику; - Методы экземпляра и статические методы, ref/out, params, значения по умолчанию и именованные аргументы; - Нулевая настройка: установите пакет, никаких изменений в файлах проекта не требуется. Источник: https://steven-giesel.com/blogPost/41599817-4457-441e-b874-1a5c67f4e7cc/if-it-quacks-part-2
10 · 1.1K ·

Рядом в ленте

..NET РазработчикДень 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три «S» в составлении промптов Лучшие промпты обладают тремя характеристик..NET РазработчикДень 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продолжение Подводные камни, которые только отнимают время 1. Использование
это сообщение
..NET РазработчикДень 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная конференция DotNext. Вернулся и делюсь впечатлениями. Я уже писал, какие..NET РазработчикФото 3 (с) Анатолий Кулаков
..NET Разработчик.NET Разработчик@NetDeveloperDiary · канал · Технологии
6 750подписчиков1 347средний охват поста
Лента площадки Открыть в Telegram

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем