![]() |
|
Модераторы: Partizan, gambit |
![]()
|
|
| stab |
|
||||||||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
Одним из основных новшеств в .NET Framework 2.0 являются Generics. Не знаю, как называются Generics по-русски, наверное, обобщения или шаблоны, но эти обобщения вещь крайне удобная, хотя и имеют некоторые ограничения.
Начав использовать шаблоны, я столкнулся с рядом проблем. Первой проблемой были, как это ни странно, операторы определения равенства и неравенства.
Получаем ошибку времени компиляции:
После чесания за ухом было найдено решение:
Что выглядит уже не так красиво, как первоначальный вариант. Кроме того, это решение имеет подводные камни. Во-первых, происходит boxing операция для value1, т.к. происходит получение интерфейса IComparable и boxing операция для value2, т.к. параметр obj метода CompareTo имеет тип object, это может снизить производительность. Во-вторых, такая операция сравнения не пройдет для ссылочных типов, если им присвоено значение null. Первую проблему можно частично решить так:
Это позволит нам избавиться от одной операции boxing, value1 по-прежнему будет нуждаться в этой операции. Вторую проблему можно решить так:
Выглядит это уже очень некрасиво. А дальше начинается самое плохое, попробуйте реализовать класс GenericCalculator, например такой:
В голову сразу приходит самое логичное и простое решение:
Но, что бы вы ни делали, это не заработает. После копания на различных ресурсах стало ясно, что шаблоны абсолютно не поддерживают операторы, это и есть корень всех проблем. Если быть совсем точным не поддерживаются статические члены классов, т.е. такая конструкция не пройдет:
Мы явно указали ограничение для параметра T и компилятор должен знать, что StaticMethod реализуется в классе T. Для меня загадка, почему было выбрано такое решение, хотя некоторые догадки есть. Думается мне, это оттого, что нет реального определения операторов для типов Int32, Double, т.д., откройте Object Browser и убедитесь сами. Даже если бы они и были, это мало бы чем помогло, т.к. все эти типы наследуются от System.ValueType, а он не дает ни какой информации об операторах, да и не нужна там эта информация. Таким образом, такой подход потребовал бы введение общего базового класса, скажем Arithmetic, с явно определенными операторами, который можно было бы использовать как ограничение на типы в шаблоне, что усложнило бы и без того нелегкую обстановку на фронте value type. Другой подход можно применять уже сейчас – это написание обертки вокруг требуемого типа с реализацией каких-либо интерфейсов, например IAddable, ISubtractable, т.д. Минусов у этого метода много, не говоря уже о неудобстве работы с такими типами, хотя если бы эти интерфейсы были изначально реализованы в подходящих классах проблем было бы меньше. Основная беда в том, что такой подход не дает возможности использования операторов, т.к. оператор должен быть статическим членом (не в этом ли проблема?), а интерфейсы не поддерживают такие члены. На иностранных ресурсах предлагалось введение в язык статических членов в интерфейсы, в том числе и операторов. С одной стороны это явно противоречит идее интерфейсов, но с другой стороны дает возможность реализовывать функциональность набора тех или иных операторов абсолютно в любом классе. Вообще, требование интерфейса реализовывать статический метод в классе выглядит несколько странно, еще более странно выглядит получение такого интерфейса, т.к. теоретически такой интерфейс может и должен получаться даже из пустой (null) ссылки на объект. Возможно, выходом из данной ситуации может быть введение static interface, тогда такой интерфейс можно будет получать из класса, а не из экземпляра класса. Этот подход немного не вписывается в текущую концепцию класса в .NET, ведь фактически, в той или иной мере, потребуется реализация виртуальных статических членов, что тоже было бы весьма полезно и одновременно сильно бы усложнило объектную модель .NET, но это уже отдельный разговор. А почему оператор должен быть статическим членом? Все очень просто – оператор должен иметь возможность оперировать даже над пустыми (null) операндами, мы ведь не можем применить нестатический метод к null объекту. Т.е. оператор, в некоторой степени, берет на себя работу конструктора, следовательно, должен быть статическим. Конечно, можно попытаться разделить статические операторы и нестатические, но это только усложнит объектную модель. Теперь о наиболее перспективном предложении по модернизации C# в направлении поддержки операторов в шаблонах. Предложен он был на иностранном сайте, к сожалению, ссылка не сохранилась, и найти в google не удается. Код все скажет сам за себя:
Тем самым мы ограничиваем параметр T только теми типами, которые поддерживают нужные нам операторы. Минус у этого метода только один – громоздкость записи. Насколько я помню, автор идеи не учитывал тип возвращаемого оператором значения, на мой взгляд, без этой информации не обойтись. В любом случае, какой бы подход не выбрали в Microsoft, требуется прозрачная и универсальная реализация понятия оператора на уровне .NET, а не на уровне избранных языков. Такая реализация приведет к потерям по скорости выполнения кода, возможно при использовании различных оптимизаций скорость выполнения может остаться на прежнем уровне. Copyright © cully, 2004. All rights reserved. ;) Ссылки по теме: http://www.gotdotnet.com/community/message....aspx?id=262238 http://www.artima.com/intv/generics3.html http://lab.msdn.microsoft.com/ProductFeedb...ackId=FDBK14659 http://lab.msdn.microsoft.com/productfeedb...05-9c64cce45d2a з.ы. что-то наш форматировщик кода подглючивает слегка... -------------------- 6, 6, 6 - the number of the beast. |
||||||||||||||||||
|
|||||||||||||||||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
cully,
что-то я торможу слегка... А часто ли приходилось Вам на практике писать классы с операторами на C# ? Ну или хотя бы на C++ ? Мне - нет, признаюсь честно (не считая операторов приведения к типу и операторов присваивания, которые ну очень часто приходилось писать - НО не в шаблонах классов). Имхо, самая основная идея (или плюс) от применения шаблонов - в возможности написания кода, повторно применяемого для реализации классов, обладающих общими чертами. В этом смысле, кривизна существующих решений по операторам отходит уже если не на второй, то на третий план. Поясню. Предположим, нужен у нас в проге класс-контейнер. ArrayList часто применяли ? Помните, как некрасиво смотрелись операции вставки и извлечения типизированных данных в/из списка ? Ага, это вам не массив (простой как доска, но зато типизированный). Вот и ответ №1, зачем нужны Generics. Дальше - больше. А ну покажите-ка мне, как реализовать на C# класс-синглетон ? Правильно, придётся писать один и тот же код для разных случаев. А вот, к примеру, на С++ всё было (до появления 2-го Framework-a) проще и яснее:
И всё, можно делать "class MySingleton: public Singleton<A> { ... }". Теперь сие доступно и на С#. И можно вспомнить ещё много случаев, при желании, когда от Генериков одни плюсы. Моё мнение: Generics - это кул. -------------------- ![]() |
|||
|
||||
| stab |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
Дело не в том часто ли мне приходится перегружать операторы, а в том, что я не могу в шаблоне применять такие простейщие операторы как ==, !=, >, <, +, -, т.д.
точно
GenericCalculator слабо написать? или еще более жизненый пример, надо сделать generic класс реализующий комплексное число, так что бы мнимой и вещественной частью мог быть любой тип, а теперь попробуйте реализовать оператор сложения двух комплексных чисел... История шаблонов началась именно с мат. алгоритмов -- матрицы, вектора, т.д. Короче, на данный момент кроме строгой типизации Generics ничего не дают, т.к. реализация любого, более или меннее, сложного алгоритма на заранее неизвестных типах сопряжена с большими трудностями.
только это мало чем отличалось от #define
не спорю, но есть к чему стремиться -------------------- 6, 6, 6 - the number of the beast. |
||||||||||
|
|||||||||||
| chipset |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 4071 Регистрация: 11.1.2003 Где: Seattle, US Репутация: 1 Всего: 165 |
Я так понимаю человеку активно использущему шаблоны в плюсах, будет трудно перейти на .NET <2.0
btw: а в VB получается тоже женерики есть? Добавлено @ 16:37
Вот что я получил по этому поводу на RSDN.. Это сообщение отредактировал(а) chipset - 17.10.2004, 16:43 --------------------
|
||||
|
|||||
| stab |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1839 Регистрация: 1.1.2003 Репутация: 22 Всего: 48 |
угу, есть:
А шаблоны могут быть реализованы как на уровне препроцессора, так и на уровне компилятора. -------------------- 6, 6, 6 - the number of the beast. |
||||
|
|||||
![]()
|
| Прежде чем создать тему, посмотрите сюда: | |
|
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |