Реализация безопасной утиной печати в С#
Посмотрев на то, как Go обрабатывает интерфейсы и любит его, я начал думать о том, как вы могли бы добиться аналогичного утиного набора текста на С# это:
var mallard = new Mallard(); // doesn't implement IDuck but has the right methods
IDuck duck = DuckTyper.Adapt<Mallard,IDuck>(mallard);
Метод DuckTyper.Adapt
использовал бы System.Reflection.Emit
для создания адаптера "на лету". Может, кто-то уже написал что-то подобное. Я предполагаю, что это не слишком отличается от того, что уже издеваются над каркасами.
Однако это приведет к исключению во время выполнения, если Mallard
фактически не имеет правильных методов IDuck
. Чтобы получить ошибку раньше во время компиляции, мне пришлось бы написать MallardToDuckAdapter
, чего я пытаюсь избежать.
Есть ли лучший способ?
edit: по-видимому, правильным термином для того, что я называю "безопасным утиным типом", является структурная типизация.
Ответы
Ответ 1
Как вы можете узнать, идет ли корова, как утка и шарлатан, как утка, если у вас нет жизни, дышащая корова перед вами?
Duck-typing - это концепция, используемая во время выполнения. Аналогичная концепция во время компиляции структурная типизация, которая AFAIK не поддерживается CLR. (CLR сосредоточен вокруг именительный набор.)
[Система структурного типа] контрастирует с номинативными системами, где сравнения основаны на явных декларациях или именах типов и утиной печати, в которых только часть структуры, доступная во время выполнения, проверяется на совместимость.
Обычный способ гарантировать, что утиная печать не исключает исключения во время выполнения, - это модульные тесты.
Ответ 2
DuckTyping для С#
Reflection.Emit используется для испускания IL, который напрямую вызывает исходный объект
Я не думаю, что эта библиотека даст вам ошибки времени компиляции, я не уверен, что это будет вполне осуществимо. Используйте Unit Tests, чтобы помочь компенсировать это.
Ответ 3
Я не думаю, что есть другой способ, с помощью которого вы получите ошибку времени компиляции.
Однако это то, что отлично подходит для Unit Testing. Вы должны написать unit test, чтобы убедиться, что
DuckTyper.Adapt<Mallard, IDuck>(mallard);
успешно отображается.
Ответ 4
Я знаю, что неявные интерфейсы (которые являются интерфейсами Go) были запланированы для VB 10 (не знаю о С#). К сожалению, они были отменены до выпуска (я думаю, что они даже не попали в бета-версию...). Было бы неплохо увидеть, появятся ли они в будущей версии .NET.
Конечно, новые типы dynamic
могут использоваться для достижения того же уровня, но это все равно не то же самое - неявные интерфейсы по-прежнему допускают сильное типирование, которое я считаю важным.