Структурная типизация в C#

в 17:35, , рубрики: golang, ооп, паттерны, метки: , ,

Когда я изучал язык Go, мне очень понравилась идея с приведением к интерфейсам по сигнатурам методов (остальная часть системы типов мне не понравилась, слишком примитивная). Это ведь статическая утиная типизация! По научному: структурная типизация.

Если вдуматься, у такого подхода куча недостатков: начиная со сложности реализации и заканчивая нарушением принципа подстановки Лисков. Ведь если у класса есть метод с нужной сигнатурой (включая название), это совсем не значит, что этот метод делает то, что ожидается.
Поэтому в мейнстрим языках, в том числе в C#, структурная типизация не поддерживается. Казалось бы на этом и сказке конец. Но недавно я осознал что в проекте, которым я сейчас занимаюсь, структурная типизация применяется. Подробности под катом.

В проекте метод применяется для работы с геттерами/сеттерами. Конечно его можно использовать и для обычных методов, но вряд ли это даст что-то хорошее.

Итак. Представьте, что у вас есть набор классов, у которых много одинаковых свойств (название и тип).
И ещё больше классов, которым для работы нужны данные из этих свойств. Например: есть класс DataItem с автосвойствами A, B и C. И класс Calculator, которому требуется значение свойства A, чтобы на его основе что-то вычислить и занести в B. А про C ему знать не надо. Также ему не надо знать и про класс DataItem, т.к. он может использоваться и с другими классами у которых есть A и B.

Как это реализовать? Заранее объявить для каждого, из таких свойств интерфейс, и каждый класс с такими свойствами пометить, как реализующий соответствующие интерфейсы. А методы классов потребителей объявлять generic-ами.

Реализация:

interface PropertyA{
  int A {get; set;}
}

class DataItem: PropertyA, PropertyB, PropertyC{
  public int A {get; set;}
  public bool B {get; set;}
  public string C {get; set;}
}

...

  void Calculate<T>(T data) where T: PropertyA, PropertyB{
    data.B = data.A > 0;
  }

Всё просто: указывая ограничения generic параметра можно собрать подходящий набор полей, и объект любого класс их реализующий передать в такой метод без всяких приведений.

Сложнее понять зачем это может пригодиться, и не является ли ситуация, когда подобная техника нужна, ещё одним запахом кода.

Автор: Vestild

Источник

Поделиться