Ответ
Утиная типизация — это концепция динамической типизации, при которой возможность использования объекта определяется не его явным типом (классом или интерфейсом), а наличием у него требуемых методов и свойств. Если объект имеет метод Quack(), его можно использовать как утку, даже если он не реализует интерфейс IDuck.
Контраст с номинативной типизацией (C#/Java): В строго типизированных языках совместимость типов проверяется на этапе компиляции по именам типов или интерфейсов.
Эмуляция в C# (где нет прямой поддержки):
-
Использование
dynamic(простейший способ, C# 4.0+):public void MakeDuckSound(dynamic duck) { // Проверка произойдёт во время выполнения (RuntimeBinderException при отсутствии метода) duck.Quack(); } var realDuck = new RealDuck(); // Имеет метод Quack() var fakeDuck = new { Quack = new Action(() => Console.WriteLine("Quack!")) }; // Анонимный тип с методом var notADuck = new object(); MakeDuckSound(realDuck); // OK MakeDuckSound(fakeDuck); // OK MakeDuckSound(notADuck); // RuntimeBinderException! -
Использование рефлексии (более гибко, но медленнее):
public bool TryMakeDuckSound(object potentialDuck) { var quackMethod = potentialDuck.GetType().GetMethod("Quack", Type.EmptyTypes); if (quackMethod != null) { quackMethod.Invoke(potentialDuck, null); return true; } return false; } -
Использование сопоставления шаблонов (C# 8.0+, более безопасно):
public void MakeDuckSound(object potentialDuck) { if (potentialDuck is IQuackable duck) // Проверка на интерфейс { duck.Quack(); } } // Требует явного определения интерфейса public interface IQuackable { void Quack(); }
Плюсы и минусы:
- Гибкость: Позволяет работать с объектами, тип которых неизвестен на этапе компиляции.
- Опасность: Потеря безопасности типов, ошибки обнаруживаются только во время выполнения.
- Производительность: Использование
dynamicи рефлексии медленнее прямых вызовов.
Видео-ответы
▶
▶
▶
▶