TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Чат .NET Разработчиков

28 Sep, 08:04

Открыть в Telegram Поделиться Пожаловаться

Репост из: .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 names = [
Duck.As(new Person()),
Duck.As(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(new { Name = "Donald", Age = 90 });

List family =
[
Duck.As(new { Name = "Huey", Age = 10 }),
Duck.As(new { Name = "Dewey", Age = 10 }),
Duck.As(new { Name = "Louie", Age = 10 }),
];

Идентичность сохраняется
Адаптеры перенаправляют вызовы методов Equals, GetHashCode и ToString к обёрнутому экземпляру, благодаря чему они корректно работают в словарях и множествах. Кроме того, можно получить доступ к исходному объекту:
var person = new Person();
Duck.As(person)
.Equals(Duck.As(person)); // true
Duck
.Unwrap(Duck.As(person)) is Person; // true

А также поддерживаются:
- Любой интерфейс, включая интерфейсы фреймворков: Duck.As(x), параметры IEnumerable и т.п.;
- Параметры интерфейса, не требующие утиной типизации (например, ILogger), продолжают принимать реализации, значения null и значения по умолчанию;
- Обобщённые интерфейсы (IContainer) и обобщённые методы [DuckTyped] с выведением аргументов типа;
- События, индексаторы и реализация интерфейса по умолчанию;
- Делегаты, лямбда-выражения и группы методов для интерфейсов с одним методом;
- Статические абстрактные члены и операторы с помощью ограничений утиной типизации (where T : IAddable) - включая обобщённую математику;
- Методы экземпляра и статические методы, ref/out, params, значения по умолчанию и именованные аргументы;
- Нулевая настройка: установите пакет, никаких изменений в файлах проекта не требуется.

Источник: https://steven-giesel.com/blogPost/41599817-4457-441e-b874-1a5c67f4e7cc/if-it-quacks-part-2
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot