Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Давайте обсудим Generics 
:(
    Опции темы
stab
Дата 12.10.2004, 02:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



Одним из основных новшеств в .NET Framework 2.0 являются Generics. Не знаю, как называются Generics по-русски, наверное, обобщения или шаблоны, но эти обобщения вещь крайне удобная, хотя и имеют некоторые ограничения.

Начав использовать шаблоны, я столкнулся с рядом проблем. Первой проблемой были, как это ни странно, операторы определения равенства и неравенства.
Код
public class GenericComparer<T>
{
public T value1;
public T value2;

public bool IsEqual()
{
 return value1 == value2;
}
}


Получаем ошибку времени компиляции:
Цитата
Operator '==' cannot be applied to operands of type 'T' and 'T'


После чесания за ухом было найдено решение:
Код
public class GenericComparer<T> where T: IComparable
{
public T value1;
public T value2;

public bool IsEqual()
{
 return value1.CompareTo(value2) == 0;
}
}


Что выглядит уже не так красиво, как первоначальный вариант. Кроме того, это решение имеет подводные камни. Во-первых, происходит boxing операция для value1, т.к. происходит получение интерфейса IComparable и boxing операция для value2, т.к. параметр obj метода CompareTo имеет тип object, это может снизить производительность. Во-вторых, такая операция сравнения не пройдет для ссылочных типов, если им присвоено значение null.

Первую проблему можно частично решить так:
Код
public class GenericComparer<T> where T: IComparable<T>


Это позволит нам избавиться от одной операции boxing, value1 по-прежнему будет нуждаться в этой операции. Вторую проблему можно решить так:
Код
public bool IsEqual()
{
return ((value1 == null && value2 == null) ||
 (value1 != null && value2 != null && value1.CompareTo(value2) == 0));
}


Выглядит это уже очень некрасиво. А дальше начинается самое плохое, попробуйте реализовать класс GenericCalculator, например такой:
Код
public class GenericCalculator<T>
{
public T value1;
public T value2;

public T Add();
public T Sub();
}


В голову сразу приходит самое логичное и простое решение:
Код
public T Add()
{
return value1 + value2;
}

public T Sub()
{
return value1 - value2;
}


Но, что бы вы ни делали, это не заработает. После копания на различных ресурсах стало ясно, что шаблоны абсолютно не поддерживают операторы, это и есть корень всех проблем. Если быть совсем точным не поддерживаются статические члены классов, т.е. такая конструкция не пройдет:
Код
public class Class1
{
public static void StaticMethod()
{
}
}

public class GenericClass1<T> where T: Class1
{
public void Method()
{
 T.StaticMethod();
}
}


Мы явно указали ограничение для параметра T и компилятор должен знать, что StaticMethod реализуется в классе T. Для меня загадка, почему было выбрано такое решение, хотя некоторые догадки есть. Думается мне, это оттого, что нет реального определения операторов для типов Int32, Double, т.д., откройте Object Browser и убедитесь сами. Даже если бы они и были, это мало бы чем помогло, т.к. все эти типы наследуются от System.ValueType, а он не дает ни какой информации об операторах, да и не нужна там эта информация. Таким образом, такой подход потребовал бы введение общего базового класса, скажем Arithmetic, с явно определенными операторами, который можно было бы использовать как ограничение на типы в шаблоне, что усложнило бы и без того нелегкую обстановку на фронте value type.

Другой подход можно применять уже сейчас – это написание обертки вокруг требуемого типа с реализацией каких-либо интерфейсов, например IAddable, ISubtractable, т.д. Минусов у этого метода много, не говоря уже о неудобстве работы с такими типами, хотя если бы эти интерфейсы были изначально реализованы в подходящих классах проблем было бы меньше. Основная беда в том, что такой подход не дает возможности использования операторов, т.к. оператор должен быть статическим членом (не в этом ли проблема?), а интерфейсы не поддерживают такие члены.


На иностранных ресурсах предлагалось введение в язык статических членов в интерфейсы, в том числе и операторов. С одной стороны это явно противоречит идее интерфейсов, но с другой стороны дает возможность реализовывать функциональность набора тех или иных операторов абсолютно в любом классе. Вообще, требование интерфейса реализовывать статический метод в классе выглядит несколько странно, еще более странно выглядит получение такого интерфейса, т.к. теоретически такой интерфейс может и должен получаться даже из пустой (null) ссылки на объект.

Возможно, выходом из данной ситуации может быть введение static interface, тогда такой интерфейс можно будет получать из класса, а не из экземпляра класса. Этот подход немного не вписывается в текущую концепцию класса в .NET, ведь фактически, в той или иной мере, потребуется реализация виртуальных статических членов, что тоже было бы весьма полезно и одновременно сильно бы усложнило объектную модель .NET, но это уже отдельный разговор.

А почему оператор должен быть статическим членом? Все очень просто – оператор должен иметь возможность оперировать даже над пустыми (null) операндами, мы ведь не можем применить нестатический метод к null объекту. Т.е. оператор, в некоторой степени, берет на себя работу конструктора, следовательно, должен быть статическим. Конечно, можно попытаться разделить статические операторы и нестатические, но это только усложнит объектную модель.

Теперь о наиболее перспективном предложении по модернизации C# в направлении поддержки операторов в шаблонах. Предложен он был на иностранном сайте, к сожалению, ссылка не сохранилась, и найти в google не удается. Код все скажет сам за себя:
Код
public class GenericCalculator<T> where T: T operator +(T, T), T operator -(T, T)
{
public T Add()
{
 return value1 + value2;
}

public T Sub()
{
 return value1 - value2;
}
}


Тем самым мы ограничиваем параметр 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.
PM MAIL WWW   Вверх
mr.DUDA
Дата 15.10.2004, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



cully,
что-то я торможу слегка... А часто ли приходилось Вам на практике писать классы с операторами на C# ? Ну или хотя бы на C++ ? Мне - нет, признаюсь честно (не считая операторов приведения к типу и операторов присваивания, которые ну очень часто приходилось писать - НО не в шаблонах классов).

Имхо, самая основная идея (или плюс) от применения шаблонов - в возможности написания кода, повторно применяемого для реализации классов, обладающих общими чертами. В этом смысле, кривизна существующих решений по операторам отходит уже если не на второй, то на третий план. Поясню.

Предположим, нужен у нас в проге класс-контейнер. ArrayList часто применяли ? Помните, как некрасиво смотрелись операции вставки и извлечения типизированных данных в/из списка ? Ага, это вам не массив (простой как доска, но зато типизированный). Вот и ответ №1, зачем нужны Generics.

Дальше - больше. А ну покажите-ка мне, как реализовать на C# класс-синглетон ? Правильно, придётся писать один и тот же код для разных случаев. А вот, к примеру, на С++ всё было (до появления 2-го Framework-a) проще и яснее:
Код
template <class T>
class Singleton
{
static T *m_instance;

static void CleanupSingleton()
{
 delete m_instance;
}

public:
static T &Instance()
{
 if (m_instance == NULL)
 {
  m_instance = new T();
  atexit(CleanupSingleton);
 }

 return *m_instance;
}
};

template<class T>
T *Singleton<T>::m_instance = NULL;


И всё, можно делать "class MySingleton: public Singleton<A> { ... }". Теперь сие доступно и на С#.

И можно вспомнить ещё много случаев, при желании, когда от Генериков одни плюсы. Моё мнение: Generics - это кул.


--------------------
user posted image
PM MAIL WWW   Вверх
stab
Дата 17.10.2004, 16:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



Цитата

что-то я торможу слегка... А часто ли приходилось Вам на практике писать классы с операторами на C# ? Ну или хотя бы на C++ ? Мне - нет, признаюсь честно (не считая операторов приведения к типу и операторов присваивания, которые ну очень часто приходилось писать - НО не в шаблонах классов).


Дело не в том часто ли мне приходится перегружать операторы, а в том, что я не могу в шаблоне применять такие простейщие операторы как ==, !=, >, <, +, -, т.д.

Цитата

Имхо, самая основная идея (или плюс) от применения шаблонов - в возможности написания кода, повторно применяемого для реализации классов, обладающих общими чертами.


точно :)

Цитата
В этом смысле, кривизна существующих решений по операторам отходит уже если не на второй, то на третий план...


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

История шаблонов началась именно с мат. алгоритмов -- матрицы, вектора, т.д. Короче, на данный момент кроме строгой типизации Generics ничего не дают, т.к. реализация любого, более или меннее, сложного алгоритма на заранее неизвестных типах сопряжена с большими трудностями.

Цитата
А вот, к примеру, на С++ всё было (до появления 2-го Framework-a) проще и яснее:

только это мало чем отличалось от #define

Цитата
Моё мнение: Generics - это кул.

не спорю, но есть к чему стремиться ;-)


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
chipset
Дата 17.10.2004, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4071
Регистрация: 11.1.2003
Где: Seattle, US

Репутация: 1
Всего: 165



Я так понимаю человеку активно использущему шаблоны в плюсах, будет трудно перейти на .NET <2.0 :stena
btw: а в VB получается тоже женерики есть? :p
Добавлено @ 16:37
Цитата
только это мало чем отличалось от #define


Вот что я получил по этому поводу на RSDN..

Это сообщение отредактировал(а) chipset - 17.10.2004, 16:43


--------------------
Цитата(Jimi Hendrix)
Well, I stand up next to a mountain
And I chop it down with the edge of my hand
PM MAIL WWW   Вверх
stab
Дата 17.10.2004, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



Цитата
btw: а в VB получается тоже женерики есть?

угу, есть:
Код

Public Class dictionary(Of entryType, keyType As IComparable)
   Public Sub add(ByVal e As entryType, ByVal k As keyType)
       Dim dk As keyType
       If k.CompareTo(dk) = 0 Then
       End If
   End Sub
   Public Function find(ByVal k As keyType) As entryType
   End Function
End Class



А шаблоны могут быть реализованы как на уровне препроцессора, так и на уровне компилятора.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0464 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.