Довольно часто объявляется универсальный интерфейс или абстрактный тип: ISomething<T>
, с намерением ожидать, что каждая реализация типа будет иметь вид: SomeClass : ISomething<SomeClass>
т. е. ссылаться на себя.
Классический пример — IEquatable
и IComparable
.
Другой распространенный шаблон - «парные классы». Где
Child : IsChildOf<Parent>
и
Parent : IsParentOf<Child, Parent>
потому что объявление IsParentOf
выглядит так:
public interface IsParentOf<TChild, TParent> where TChild : IsChildOf<TParent>
Вы хотите заявить, что у Parent
есть дети... но только такие дети:
Dog : IsParentOf<Puppies,Dog>
и Cat : IsParentOf<Kittens,Cat>
. Но вы не можете непреднамеренно объявить Cow : IsParentOf<Lamb, Cow>
... потому что Lamb не реализует IsChildOf<Cow>
Но обратите внимание, что намерение состоит в том, что в строке Parent : IsParentOf<Child, Parent>
... всегда ожидается, что второй общий параметр будет объявленным типом.
Таким образом, можно представить себе новое ключевое слово Typing TThis
таким образом, что IsParentOf
станет:
public interface IsParentOf<TChild> where TChild : ChildOf<TThis>
Вопрос 0: Правильно ли я считаю, что этой концепции не существует в C# (и ничего подобного)
Вопрос 1: Есть ли какая-то конкретная причина, по которой он не может существовать? то есть что идея на самом деле не имеет смысла в определенных случаях / не может на самом деле сделать то, что я себе представляю.
Или это просто классическое «функции не существуют, пока кто-то не потратит время и ресурсы на то, чтобы они существовали… и эта функция не оправдывает усилий (пока)»?
Вы ищете что-то вроде этого?
Кроме того, иметь класс для «маленьких» собак и один для взрослых довольно странно, ИМХО. Что вы делаете, когда ваш Puppy
растет?
@MakePeaceGreatAgain Суть примера не в этом... дело в том, что эти классы существуют парами. Возможно, «Транспорт» и «Пригородный» — лучшие метаклассы. Поезда, автомобили и велосипеды — все виды транспорта, и у всех есть пассажиры… но TrainPassenger, Driver и Cyclist очень разные, но существуют в отображении 1-1.
@nvoigt мой текущий конкретный случай: «Разнообразие различных бизнес-объектов, представляющих путешествия ... каждый из которых имеет набор этапов. Различные типы путешествий имеют некоторые общие черты и другие вещи, которые уникальны для типа путешествия. У разных типов ног есть что-то общее, а что-то уникальное для ног этого типа путешествия».
@Уборщик. Да, я так думаю. Я не читал все, но похоже именно то, о чем я говорю.
@Sweeper Я бы с радостью принял ответ «нет, этого не существует. Но да, определенно мог бы. Цитата: это было предложено и обсуждено здесь». (Вероятно, ссылка как на вашу ссылку, так и на другую версию в csharplang, ссылка внизу темы: github.com/dotnet/csharplang/discussions/169)
Можете ли вы показать несколько конкретных примеров использования «парных классов»? Если у 2 классов есть отображение 1-1, насколько мне известно, вам не нужен общий.
Я прав, думая, что этой концепции не существует в С#?
Это не существует как языковая функция. Вы не можете попросить язык заставить пользователей фактически указать тип реализации в качестве аргумента типа интерфейса. В вашем примере IsParentOf
я мог бы написать:
class SomethingElse : IsParentOf<Puppies, Dog>
даже если к TParent
было добавлено дополнительное ограничение (это известно как любопытно повторяющийся шаблон шаблона )
public interface IsParentOf<TChild, TParent>
where TChild : IsChildOf<TParent>
where TParent: IsParentOf<TChild, TParent>
Потому что Dog
действительно реализует IsParentOf<Puppies, Dog>
.
Была проблема , связанная с добавлением : this
общего ограничения, чтобы его можно было применить, что привело к этому предложению.
Это определенно теоретически возможно реализовать — в Swift есть тип Self
, и, насколько мне известно, в Rust и Scala тоже есть что-то подобное. Выяснение деталей того, как эта функция будет взаимодействовать с существующими функциями C#, как всегда, сложная часть :)
И не только существующие функции C# — хотя мы, пользователи C#, любим приукрашивать это, .NET Framework также является основой для многих других языков. :P Эта функция почти наверняка потребует изменений во время выполнения.
За 22 года работы на C# я ни разу не сталкивался с тем, что вы назвали "парными классами". Есть ли у вас примеры из реальной жизни, где это было бы необходимо или даже распространено?