Почему в C# Generics нет TThis для самореферентных интерфейсов?

Довольно часто объявляется универсальный интерфейс или абстрактный тип: 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: Есть ли какая-то конкретная причина, по которой он не может существовать? то есть что идея на самом деле не имеет смысла в определенных случаях / не может на самом деле сделать то, что я себе представляю.

Или это просто классическое «функции не существуют, пока кто-то не потратит время и ресурсы на то, чтобы они существовали… и эта функция не оправдывает усилий (пока)»?

За 22 года работы на C# я ни разу не сталкивался с тем, что вы назвали "парными классами". Есть ли у вас примеры из реальной жизни, где это было бы необходимо или даже распространено?

nvoigt 23.02.2023 09:48

Вы ищете что-то вроде этого?

Sweeper 23.02.2023 10:03

Кроме того, иметь класс для «маленьких» собак и один для взрослых довольно странно, ИМХО. Что вы делаете, когда ваш Puppy растет?

MakePeaceGreatAgain 23.02.2023 10:04

@MakePeaceGreatAgain Суть примера не в этом... дело в том, что эти классы существуют парами. Возможно, «Транспорт» и «Пригородный» — лучшие метаклассы. Поезда, автомобили и велосипеды — все виды транспорта, и у всех есть пассажиры… но TrainPassenger, Driver и Cyclist очень разные, но существуют в отображении 1-1.

Brondahl 23.02.2023 10:18

@nvoigt мой текущий конкретный случай: «Разнообразие различных бизнес-объектов, представляющих путешествия ... каждый из которых имеет набор этапов. Различные типы путешествий имеют некоторые общие черты и другие вещи, которые уникальны для типа путешествия. У разных типов ног есть что-то общее, а что-то уникальное для ног этого типа путешествия».

Brondahl 23.02.2023 10:20

@Уборщик. Да, я так думаю. Я не читал все, но похоже именно то, о чем я говорю.

Brondahl 23.02.2023 10:22

@Sweeper Я бы с радостью принял ответ «нет, этого не существует. Но да, определенно мог бы. Цитата: это было предложено и обсуждено здесь». (Вероятно, ссылка как на вашу ссылку, так и на другую версию в csharplang, ссылка внизу темы: github.com/dotnet/csharplang/discussions/169)

Brondahl 23.02.2023 10:24

Можете ли вы показать несколько конкретных примеров использования «парных классов»? Если у 2 классов есть отображение 1-1, насколько мне известно, вам не нужен общий.

shingo 23.02.2023 10:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
53
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 Эта функция почти наверняка потребует изменений во время выполнения.

Jeroen Mostert 23.02.2023 10:47

Другие вопросы по теме