Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active October 7, 2025 11:29
Show Gist options
  • Save sunmeat/4016527c07573d53566dd6e3293bf9bb to your computer and use it in GitHub Desktop.
Save sunmeat/4016527c07573d53566dd6e3293bf9bb to your computer and use it in GitHub Desktop.
foreach та качина типізація
using System.Text;
namespace DuckTypingDemo
{
class Program
{
static void Main()
{
Console.OutputEncoding = Encoding.UTF8;
var collection = new MonsterCollection(); // припустимо, що є певна колекція чогось
// перебирання елементів виглядає легко і приємно
foreach (var item in collection)
{
Console.Write(item + " "); // 0 1 2 3 4
}
Console.WriteLine();
// але, форич вище насправді перетворюється на щось нахлобучене накшталт
for (MonsterEnumerator tmp = collection.GetEnumerator(); tmp.MoveNext();)
{
int item = tmp.Current;
Console.Write(item + " ");
}
Console.WriteLine();
// щоб з'явилася можливість перебирати елементи колекції foreach, необхідно:
// 1) у класі-колекції зробити метод GetEnumerator(), який буде повертати посилання на спеціальний об'єкт-перелічувач
// 2) забезпечити наявність окремого класу-перелічувача (енумератора), цей клас можна розмістити як зовні від класу колекції, так і в тілі класу-колекції
// 3) у класі-перелічувачі повинен бути метод MoveNext, для перевірки наявності неопрацьованих (необроблених) об'єктів колекції
// 4) у класі-перелічувачі повинна бути властивість Сurrent, яка за запитом зможе видавати посилання на поточний елемент колекції
}
}
// https://habr.com/ru/articles/41377/
// https://uk.wikipedia.org/wiki/%D0%9A%D0%B0%D1%87%D0%B8%D0%BD%D0%B0_%D1%82%D0%B8%D0%BF%D1%96%D0%B7%D0%B0%D1%86%D1%96%D1%8F
// качина типизація (duck typing): це концепція, коли об'єкт поводиться як певний тип,
// якщо має необхідні методи/властивості, без явної реалізації інтерфейсу.
// можна не використовувати явно стандартні інтерфейси (наприклад, ienumerable, ienumerator),
// щоб продемонструвати, як foreach працює на основі "качиного" типу -
// якщо є Getenumerator(), MoveNext() та властивість Current, то цього достатньо для ітератора.
// приклад ілюструє гнучкість С#, але все ж рекомендується ЯВНО використовувати інтерфейси для наочності та типобезпеки.
/* форич не перевіряє наявність інтерфейсу.
// чому так? - історична сумісність.
// на ранніх етапах розвитку C#, стандартні колекції (наприклад, масиви) не реалізовували інтерфейси IEnumerable чи IEnumerator.
// так звана КАЧИНА ТИПІЗАЦІЯ дозволяла використовувати такі колекції у foreach без необхідності зміни їх внутрішньої реалізації.
/* качина типізація (duck typing) у C# — це концепція, запозичена з динамічних мов програмування
* (як Python чи Ruby), де об'єкт вважається "відповідним" певному типу не через спадкування
* чи явну реалізацію інтерфейсу, а через наявність необхідних методів і властивостей
* у потрібний момент.
* Класична фраза: "Якщо воно ходить, як качка, і крякає, як качка, то це качка".
* У C# це НЕ повноцінна динамічна типізація (мова залишається статично типізованою),
* а обмежена структурна типізація (structural typing), яка застосовується в конкретних
* сценаріях, таких як ітерація foreach, виклики делегатів, LINQ-запити чи dynamic об'єкти.
Навіщо duck typing у C#?
C# — це гібридна мова: статична типізація забезпечує безпеку та продуктивність на етапі
компіляції, але duck typing додає гнучкості для певних випадків, де явна реалізація
інтерфейсу створювала б зайвий "баласт" (boilerplate-код). Основні причини існування:
- Спрощення коду та сумісність: Дозволяє використовувати об'єкти "як є", без примусової
реалізації інтерфейсів. Наприклад, для foreach достатньо мати метод GetEnumerator(),
який повертає об'єкт з MoveNext() та властивістю Current. Компілятор не вимагає
IEnumerable<int>, бо структурно це співпадає. Це робить код лаконічнішим, особливо
для простих колекцій чи інтеграції з динамічними даними (JSON, API-відповіді).
- Підтримка динамічних сценаріїв: З появою dynamic (C# 4.0), duck typing дозволяє працювати
з невідомими типами на runtime, наприклад, у скриптингу чи інтеропі з COM/JavaScript.
Без цього C# був би менш універсальним для enterprise-задач.
- Історичний та еволюційний аспект: Microsoft додала елементи duck typing, щоб наблизити C#
до динамічних мов, зберігаючи сильну типізацію. Як зазначає Ерік Ліперт (колишній архітектор
мови), це "робота з об'єктами без явного називання інтерфейсів", що корисно для розширення
без ламання коду.
*/
class MonsterEnumerator
{
public int Current { get; private set; }
private int step;
public bool MoveNext()
{
if (step >= 5) return false;
Current = step++;
return true;
}
}
class MonsterCollection
{
// List<Monster> monsters = new List<Monster>();
public MonsterEnumerator GetEnumerator()
{
return new MonsterEnumerator();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment