|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
|||||||||||
Преобразование типов в ограниченных обобщенных классах21.08.2020, 17:08. Показов 10689. Ответов 28
Здравствуйте, друзья.
Изучаю C#. Соответственно экспериментирую с кодом в процессе изучения. Такой вопрос. Имеется допустим иерархия классов:
на несуразность примера, это просто для экспериментов). Так вот выдает ошибку о невозможности преобразования:
Можете, пожалуйста, объяснить такое поведение? В чем я ошибаюсь?
0
|
|||||||||||
| 21.08.2020, 17:08 | |
|
Ответы с готовыми решениями:
28
Арифметические действия в обобщенных классах Взаимосвязь типов в двух обобщённых классах Преобразование типов данных в классах |
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|||||||
| 21.08.2020, 17:26 | |||||||
Сообщение было отмечено loyalist28 как решение
РешениеВ наследовании бывают ветвления, если два типа находятся на одном уровне иерархии, то один из них нельзя привести к другому. Полиморфические преобразования работают только вверх или вниз по иерархии, горизонтально не работают. Поскольку обобщенный тип должен работать со всеми классами, удовлетворяющими условие наследования от Base, постольку компилятор должен предполгать, что возможно приведение типов на одном уровне, о чем и сообщает. Пример той же ошибки без обобщений:
2
|
|||||||
|
1595 / 600 / 185
Регистрация: 05.12.2015
Сообщений: 970
|
||
| 21.08.2020, 17:53 | ||
|
тогда этот вопрос не задал бы обобщения как правило используют для вызова из производных классов виртуальных функций и свойств, которые определяются в базовом, зачастую пустые.
1
|
||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
|||||||
| 23.08.2020, 09:53 [ТС] | |||||||
0
|
|||||||
|
1845 / 1187 / 501
Регистрация: 14.10.2018
Сообщений: 3,204
|
||
| 23.08.2020, 11:44 | ||
Сообщение было отмечено loyalist28 как решение
РешениеОбъект d на 29 строке кода имеет 2 публичных метода ShowClassName() с одинаковым названием. Один метод из базового класса, другой из текущего.Обобщение where T : Base может принимать в качестве T класс Base или любой унаследованный от него. Данное обобщение работает именно с классом Base и все паблик поля, свойства и методы от данного класса он может вызывать внутри себя.И вот происходит вызов метода на 21 строке, но какой? ведь у объекта d их по факту 2, но обобщение может работать только с одним, потому и происходит вызов метода класса Base, так как о производных методах обобщение ничего не знает.
0
|
||
|
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
|
|||||||
| 23.08.2020, 11:48 | |||||||
0
|
|||||||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|
| 23.08.2020, 12:32 | |
Сообщение было отмечено loyalist28 как решение
Решение
loyalist28, все по той же причине: обобщенный метод должен работать со всеми типами и не у всех будет затенение метода, следовательно используется базовая реализация, хоть по факту переменная и будет иметь тип Derived.
1
|
|
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
|
| 23.08.2020, 14:44 [ТС] | |
|
Спасибо, друзья. Теперь все понятно.
0
|
|
|
1595 / 600 / 185
Регистрация: 05.12.2015
Сообщений: 970
|
|||||||
| 23.08.2020, 20:45 | |||||||
|
в первом посте я написал для чего это надо - виртуальные функции
0
|
|||||||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
||
| 24.08.2020, 02:05 [ТС] | ||
|
Добавлено через 14 минут Ну и заодно понял очень полезную вещь, что при создании класса Generic<T>, в его методе Method() сразу прописывается ссылка на реализацию ShowClassName из Base, так как Generic<T> имеет информацию только о нем, а о его потомках ничего не знает. Тогда действительно, что даже если передать в Method() объект типа Derived,положить его в переменную типа Derived, то все равно реализация из Base будет вызвана. Хотя это и немного необычно )
0
|
||
|
1522 / 507 / 126
Регистрация: 09.01.2018
Сообщений: 1,536
|
||||||||||||||||||
| 24.08.2020, 08:32 | ||||||||||||||||||
На самом деле, такие преобразования разрешены в спецификации языка, поэтому компилятор не выдает ошибок. А для параметров типа разрешены не все преобразования. В частности, преобразование 'T' в производный тип не разрешается. Потому компилятор сразу выдает ошибку. Вот небольшой список разрешенных преобразований:
В третьей попытке все прекрасно, поскольку используется безопасное приведение типов. Подробнее о преобразовании типов и параметров типа можно прочитать по ссылкам ниже (спецификация - Implicit, Explicit): https://docs.microsoft.com/en-... parameters https://docs.microsoft.com/en-... parameters Внимание: Не читайте на русском языке.
2
|
||||||||||||||||||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
|||
| 24.08.2020, 13:32 [ТС] | |||
|
Добавлено через 4 минуты
0
|
|||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|||||||
| 24.08.2020, 14:15 | |||||||
Затенение создает новую запись в таблице методов типа, переопределение виртуального метода меняет адрес реализации уже существующей записи — той, которую создал класс, объявивший виртуальный метод.
1
|
|||||||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
|
| 25.08.2020, 01:49 [ТС] | |
|
Спасибо, очень доходчиво и познавательно.
0
|
|
|
1522 / 507 / 126
Регистрация: 09.01.2018
Сообщений: 1,536
|
|||||||
| 25.08.2020, 03:44 | |||||||
|
Вы правильно предполагали. Привязка методов, даже виртуальных, даже в обобщенных классах, выполняется во время компиляции. А во время компиляции тип переменной - это ограничивающий тип. Если метод виртуальный, то для определения метода используется фактический тип объекта, на который ссылается переменная. (привязка, тем не менее, все также выполняется во время компиляции, там другой механизм). Когда вы создаете в коде закрытый тип (имеющий действительный тип данных), компилятор лишь проверяет, что параметр типа соответствует указанным ограничениям. И все. К слову, если ограничивающий тип не определен, то он имеет тип 'object'. Т.е. ограничивающий тип есть всегда и он известен во время компиляции. Однако типом 'Derived' он станет только во время выполнения. Но в это время метод уже привязан. Получается, что изменяя действительный тип данных в коде, вы не можете повлиять на определение вызываемого метода, если он не виртуальный. Это всегда будет метод ограничивающего типа. Тем не менее, один интересный выход все же есть. Если фактический тип будет известен лишь во время выполнения, то для вызова метода производного класса можно использовать переменную типа 'dynamic'. Этот тип может ссылаться на объект любого типа, а проверка на соответствие будет отложена до времени выполнения. И это свойство можно использовать.
1
|
|||||||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
||
| 25.08.2020, 03:59 [ТС] | ||
|
Спасибо, очень доходчиво и познавательно.
0
|
||
|
1522 / 507 / 126
Регистрация: 09.01.2018
Сообщений: 1,536
|
|||||||
| 25.08.2020, 04:18 | |||||||
Метод базового класса должен возвращать совсем другой тип значения. Но это же универсальный шаблон. Другой пример. Если бы так оно было, то как вызвать нужную реализацию, имея экземпляр производного класса? Выполняем приведение к одному из базовых, но компилятор тем не менее вызывает метод по фактическому типу объекта. Скорее всего есть еще причины и не мало. Увы обо всех я не знаю.
1
|
|||||||
|
1845 / 1187 / 501
Регистрация: 14.10.2018
Сообщений: 3,204
|
||
| 25.08.2020, 12:52 | ||
|
Если брать за основу вышеуказанное наследование where T : A, то обобщение будет работать с классом A. А что касается иерархии - сделайте проще - сперва удалите всю иерархию, потом снова создайте, потом удалите, потом создайте. Будет ли вызываемый метод MethodA() при этом меняться - однозначно нет. В этом и заключается суть строгой типизации, и вы всегда знаете как работает ваш код.
1
|
||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
||||
| 25.08.2020, 13:02 | ||||
|
Не забывайте, что обобщения — это не плюсовые шаблоны, а обобщенные типы, т.е. должы работать в любой ситуации, в том числе когда сконструированный тип создается во время выполнения, о чем компилятор физически знать не может.
0
|
||||
|
0 / 0 / 0
Регистрация: 24.04.2020
Сообщений: 18
|
||
| 25.08.2020, 17:47 [ТС] | ||
|
Вы хотите сказать, что компилятор не знает о том, что Derived наследует от Base?? А как же мы тогда можем операции приведения типов проводить и при этом компилятор выдает нам ошибку времени компиляции при преобразовании друг к другу не родственных типов? Или пользоваться членами базового класса в экземпляре класса наследника? О_о
0
|
||
| 25.08.2020, 17:47 | |
|
Помогаю со студенческими работами здесь
20
Сравнение обобщённых типов Динамическое изменение типа объекта (для обобщённых типов)
Инициализация ссылочных типов в структурах\классах Обработка исключений в классах для пользовательских типов Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|