Re[21]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 09:57
Оценка:
Здравствуйте, eao197, Вы писали:

AVK>>3) Смысла в вызове экземпляра делегата для другого объекта я вобще не вижу. Проще создать для него другой экземпляр того же делегата.


E>Если ты его не видишь, то это не значит, что смысла нет. Я вот, иногда использовал сначала выбор указателя на метод объекта, который нужно будет вызвать в текущих условиях, затем получал откуда-то объект и применял к нему этот указатель.


А зачем? Не, ну можно конечно сделать статический метод и передавать в него ссылку на экземпляр, но лично мне такое ни разу не пригодилось.

AVK>>О, мне нравится твой подход. Буквально абзацем выше ты фактически признался в том что нечетко представляешь, что такое делегат, а уже сделал вывод что в делегате каких то возможностей нет, и, хуже того, что мы их не дождемся.


E>Значит ошибся по незнанию.


Так проблема то не в том что ошибся, все ошибаются, а в том что на основании неопределенности ты делаешь выводы.

AVK>>А так в винформсах и есть. Влад тебе о другом говорил — о решении проблем диспетчеризации декларативно.


E>А я ему и ответил, что нафиг мне такая декларативная диспетчеризация, если работать с ее результатами будет неудобно.


Не, ты привязался к конкретно виндовым сообщениям. Вариант с виртуальными методами приводит к большему объему работ и со стороны производителя библиотеки, и со стороны прикладного программиста, а результат получается не очень гибким. В тех же виндовых сообщениях все равно никто не делает виртуальные методы для всех возможных сообщений, только распространенных. Есть и еще одна проблема — ПК вот что то молчит, но виртуальные методы раздувают публичный контракт и создают огромные классы.

AVK>>Заметь, это весь пользовательский код.


E>Похожие штуки на сигналах/слотах Qt делаются без проблем.


Пример?

E>А вот в C#, похоже, для любой фенички нужно синтаксическую фишечку добавлять


С чего ты взял? Атрибуты и делегаты это универсальная механика, а не фенечка для декларативной диспетчеризации.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[25]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 09:57
Оценка: :)))
Здравствуйте, Cyberax, Вы писали:

C>Я предпочитаю ISO — так как они работают по своим же стандартам качества

C>(в отличие от ECMA).

А для С++ ISO-стандарт есть?
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[26]: Функциональные типы (параллельная ветка)
От: Cyberax Марс  
Дата: 28.06.05 10:12
Оценка: 1 (1) +3 :)
AndrewVK wrote:

> C>Я предпочитаю ISO — так как они работают по своим же стандартам

> качества
> C>(в отличие от ECMA).
> А для С++ ISO-стандарт есть?

Естественно! ISO/IEC 14882.

Кстати, такое долгое время на выпуск стандарта С++ как раз и связано с
тем, что они его делают качественно. По сути мы сейчас работаем на
стандарте 94 года (принятом в 98 году с сервиспаком в 2003).

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[22]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 10:29
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, eao197, Вы писали:


AVK>>>3) Смысла в вызове экземпляра делегата для другого объекта я вобще не вижу. Проще создать для него другой экземпляр того же делегата.


E>>Если ты его не видишь, то это не значит, что смысла нет. Я вот, иногда использовал сначала выбор указателя на метод объекта, который нужно будет вызвать в текущих условиях, затем получал откуда-то объект и применял к нему этот указатель.


AVK>А зачем? Не, ну можно конечно сделать статический метод и передавать в него ссылку на экземпляр, но лично мне такое ни разу не пригодилось.


Ну вот я Владу приводил пример с конечным автоматом, ему не понравилось
Например, когда объект имеет три метода: make_owner_view, make_group_view, make_other_view (скажем формирует представление объекта для владельца, для группы, в которую входит владелец, для всех остальных). В зависимости от того, кем является пользователь по отношению к объектам приложения, определяется, какой метод нужно вызвать. Причем такое определение возможно еще до того, объект будет создан/получен.
Еще один вариант. Объект представляет собой Protocol Data Unit (PDU) какого нибудь протокола. В разных версиях протокола ограничения на размеры и значения полей могут различаться. Поэтому для проверки корректности объекта объект может предоставлять несколько методов: check_ver_3_3, check_ver_3_4, check_ver_5_0. В зависимости от используемой версии протокола можно один раз сохранить указатель на конкретный метод, а затем применять его для работы со всеми PDU в рамках сессии.
Конечно, здесь можно было бы делать статические методы, но, имхо, с указателями на методы проще, удобнее и компактнее, особенно, если методы виртуальные.

AVK>>>А так в винформсах и есть. Влад тебе о другом говорил — о решении проблем диспетчеризации декларативно.


E>>А я ему и ответил, что нафиг мне такая декларативная диспетчеризация, если работать с ее результатами будет неудобно.


AVK>Не, ты привязался к конкретно виндовым сообщениям. Вариант с виртуальными методами приводит к большему объему работ и со стороны производителя библиотеки, и со стороны прикладного программиста, а результат получается не очень гибким.


Заметь, что про виртуальные методы я вообще не говорил. Я просто упомянул механизм, который был реализован в windowsx.h давным-давно: распаковщики сообщений, которые автоматически вытаскивали из wParam, lParam значения аргументов и вызывали функцию удобного для этого сообщения формата. И эти функции вовсе не должны были быть виртуальными.

AVK>>>Заметь, это весь пользовательский код.


E>>Похожие штуки на сигналах/слотах Qt делаются без проблем.


AVK>Пример?


http://doc.trolltech.com/3.3/qmenubar.html
QPopupMenu *file = new QPopupMenu( this );

file->insertItem( p1, "&Open",  this, SLOT(open()), CTRL+Key_O );
file->insertItem( p2, "&New", this, SLOT(news()), CTRL+Key_N );

menu = new QMenuBar( this );

menu->insertItem( "&File", file );

Полный код примера здесь: http://doc.trolltech.com/3.3/menu-example.html
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[23]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 10:59
Оценка: +1 -1
Здравствуйте, eao197, Вы писали:

E>Например, когда объект имеет три метода: make_owner_view, make_group_view, make_other_view (скажем формирует представление объекта для владельца, для группы, в которую входит владелец, для всех остальных). В зависимости от того, кем является пользователь по отношению к объектам приложения, определяется, какой метод нужно вызвать. Причем такое определение возможно еще до того, объект будет создан/получен.


Для этого можно создать делегат динамически.

E>Еще один вариант. Объект представляет собой Protocol Data Unit (PDU) какого нибудь протокола. В разных версиях протокола ограничения на размеры и значения полей могут различаться. Поэтому для проверки корректности объекта объект может предоставлять несколько методов: check_ver_3_3, check_ver_3_4, check_ver_5_0. В зависимости от используемой версии протокола можно один раз сохранить указатель на конкретный метод, а затем применять его для работы со всеми PDU в рамках сессии.


Тоже самое.

E>Конечно, здесь можно было бы делать статические методы, но, имхо, с указателями на методы проще, удобнее и компактнее, особенно, если методы виртуальные.


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

E>Заметь, что про виртуальные методы я вообще не говорил. Я просто упомянул механизм, который был реализован в windowsx.h давным-давно: распаковщики сообщений, которые автоматически вытаскивали из wParam, lParam значения аргументов и вызывали функцию удобного для этого сообщения формата. И эти функции вовсе не должны были быть виртуальными.


Ага, можно еще на макросах, как это было в ВС++ версии с 4. Еще можно как в WTL на шаблонах поизгаляться. Только решение с атрибутами проще и понятнее.

E>>>Похожие штуки на сигналах/слотах Qt делаются без проблем.


AVK>>Пример?


E>http://doc.trolltech.com/3.3/qmenubar.html

E>
E>QPopupMenu *file = new QPopupMenu( this );

file->>insertItem( p1, "&Open",  this, SLOT(open()), CTRL+Key_O );
file->>insertItem( p2, "&New", this, SLOT(news()), CTRL+Key_N );

E>menu = new QMenuBar( this );

menu->>insertItem( "&File", file );
E>


Это называется декларативное задание, да? Ты кажется не понимаешь кардинального отличия моего кода от этого — в моем случае обработка и все, что с ней связано, указывается по месту. Для того чтобы добавить новый обработчик не нужно править код создания меню. Вобще. А если еще учесть что и меню задается декларативно, а не той кашей, что ты привел, то отличия видны с расстояния в 10 км.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[24]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 11:33
Оценка: +1 -3
Здравствуйте, AndrewVK, Вы писали:

E>>Конечно, здесь можно было бы делать статические методы, но, имхо, с указателями на методы проще, удобнее и компактнее, особенно, если методы виртуальные.


AVK>А с динамическим созданием делегатов, особенно если их совместить с декларативным заданием обработчиков, еще удобнее. Если бы ты все таки научился так описывать примеры, чтобы их можно было полностью понять, то я бы тебе даже пример привел.


Для начала объясни, что тебе вот здесь не понятно:

E>>Еще один вариант. Объект представляет собой Protocol Data Unit (PDU) какого нибудь протокола. В разных версиях протокола ограничения на размеры и значения полей могут различаться. Поэтому для проверки корректности объекта объект может предоставлять несколько методов: check_ver_3_3, check_ver_3_4, check_ver_5_0. В зависимости от используемой версии протокола можно один раз сохранить указатель на конкретный метод, а затем применять его для работы со всеми PDU в рамках сессии.


Или тебе конкретные протоколы нужно перечислить? Например, Short Message Peer-to-Peer (SMPP) или GSM 03.40, или GSM 11.11. Хотя такие же штуки (проверки) можно и на XML-ных протоколах делать.

E>>Заметь, что про виртуальные методы я вообще не говорил. Я просто упомянул механизм, который был реализован в windowsx.h давным-давно: распаковщики сообщений, которые автоматически вытаскивали из wParam, lParam значения аргументов и вызывали функцию удобного для этого сообщения формата. И эти функции вовсе не должны были быть виртуальными.


AVK>Ага, можно еще на макросах, как это было в ВС++ версии с 4. Еще можно как в WTL на шаблонах поизгаляться. Только решение с атрибутами проще и понятнее.


И неудобнее, в очередной раз рискну повторить. Кстати, вполне возможно, что windowsx.h еще в BC++ 3.1 был.

E>>>>Похожие штуки на сигналах/слотах Qt делаются без проблем.


AVK>>>Пример?


E>>http://doc.trolltech.com/3.3/qmenubar.html

E>>
E>>QPopupMenu *file = new QPopupMenu( this );

file->>>insertItem( p1, "&Open",  this, SLOT(open()), CTRL+Key_O );
file->>>insertItem( p2, "&New", this, SLOT(news()), CTRL+Key_N );

E>>menu = new QMenuBar( this );

menu->>>insertItem( "&File", file );
E>>


AVK>Это называется декларативное задание, да?


Нет, это сравнимо с объемом кода и, имхо, его понятность и более правильной декомпозицией.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[25]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 12:02
Оценка: -1
Здравствуйте, eao197, Вы писали:

E>Для начала объясни, что тебе вот здесь не понятно:

E>

E>>>Еще один вариант. Объект представляет собой Protocol Data Unit (PDU) какого нибудь протокола. В разных версиях протокола ограничения на размеры и значения полей могут различаться. Поэтому для проверки корректности объекта объект может предоставлять несколько методов: check_ver_3_3, check_ver_3_4, check_ver_5_0. В зависимости от используемой версии протокола можно один раз сохранить указатель на конкретный метод, а затем применять его для работы со всеми PDU в рамках сессии.


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

AVK>>Ага, можно еще на макросах, как это было в ВС++ версии с 4. Еще можно как в WTL на шаблонах поизгаляться. Только решение с атрибутами проще и понятнее.


E>И неудобнее, в очередной раз рискну повторить.


Чем?

E> Кстати, вполне возможно, что windowsx.h еще в BC++ 3.1 был.


Таблица обработчиков на макросах появилась точно не раньше 4.0. А в 3.1 были хитрые динамические виртуальные методы с номерком, задаваемым декларативно. Что то вроде dispid в СОМ, только без преобразования из имени метода в это id. А вирутальные методы это уже более высокоуровневая механика была, поверх этой.

AVK>>Это называется декларативное задание, да?


E>Нет, это сравнимо с объемом кода


Абсолютно несравнимо.

E> и, имхо, его понятность и более правильной декомпозицией.


Ты видимо так и не понял. Хорошо, задам более простой вопрос. Пусть у тебя есть меню, построенное таким образом, что ты привел. Во скольких местах тебе придется поравить код для добавления нового пункта? Ну или хотя бы просто хоткея?
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[26]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 12:33
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, eao197, Вы писали:


E>>Для начала объясни, что тебе вот здесь не понятно:

E>>

E>>>>Еще один вариант. Объект представляет собой Protocol Data Unit (PDU) какого нибудь протокола. В разных версиях протокола ограничения на размеры и значения полей могут различаться. Поэтому для проверки корректности объекта объект может предоставлять несколько методов: check_ver_3_3, check_ver_3_4, check_ver_5_0. В зависимости от используемой версии протокола можно один раз сохранить указатель на конкретный метод, а затем применять его для работы со всеми PDU в рамках сессии.


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


Видишь ли, мне по работе часто приходится много чего объяснять и на доступность объяснения жалуются крайне редко. А ваше с Владом непонимание, вероятно, вызвано тем, что мы по жизни работаем в разных прикладных направлениях.

Вот, что я имел в виду:
class    pdu_t
    {
    public :
        virtual void check_ver_3_3() const = 0;
        virtual void check_ver_3_4() const = 0;
        virtual void check_ver_5_0() const = 0;
        ...
    };
    
class submit_sm_t : public pdu_t { /* реализация методов check_ver_* */ };
class deliver_sm_t : public pdu_t { /* реализация методов check_ver_* */ };
class data_sm_t : public pdu_t { /* реализация методов check_ver_* */ };
...

typedef void (pdu_t::*checker_t)();

class    session_t
    {
    private :
        checker_t    m_checker;
        
    public :
        void established( version_t & version )
            {
                if( 0x33 == version )
                    m_checker = &pdu_t::check_ver_3_3;
                else if( 0x34 == version )
                    m_checker = &pdu_t::check_ver_3_4;
                else
                    m_checker = &pdu_t::check_ver_5_0;
                ...
            }
            
        void process_outgoing( const pdu_t & pdu )
            {
                // Проверяем корректность PDU.
                (pdu.*m_checker)();
                ...
            }
        ...
    };


AVK>>>Ага, можно еще на макросах, как это было в ВС++ версии с 4. Еще можно как в WTL на шаблонах поизгаляться. Только решение с атрибутами проще и понятнее.


E>>И неудобнее, в очередной раз рискну повторить.


AVK>Чем?


Тем, что из объекта Message нужно извлечь wParam, lParam, а затем из них уже извлечь нужные мне значения. А вот макросы из windowsx.h с этим прекрасно справлялись.

E>> Кстати, вполне возможно, что windowsx.h еще в BC++ 3.1 был.


AVK>Таблица обработчиков на макросах появилась точно не раньше 4.0. А в 3.1 были хитрые динамические виртуальные методы с номерком, задаваемым декларативно. Что то вроде dispid в СОМ, только без преобразования из имени метода в это id. А вирутальные методы это уже более высокоуровневая механика была, поверх этой.


Это ты про OWL из Borland-а? А я ее не использовал, работал на чистом WinAPI.

E>> и, имхо, его понятность и более правильной декомпозицией.


AVK>Ты видимо так и не понял. Хорошо, задам более простой вопрос. Пусть у тебя есть меню, построенное таким образом, что ты привел. Во скольких местах тебе придется поравить код для добавления нового пункта? Ну или хотя бы просто хоткея?


Если этот пункт статический (не появляется в произвольный момент), то в одном -- там где меню формируется.
Или ты имел в виду и обработчик события так же? Если с обработчиком события -- то в двух, естественно.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[27]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 13:36
Оценка:
Здравствуйте, eao197, Вы писали:

E>Видишь ли, мне по работе часто приходится много чего объяснять и на доступность объяснения жалуются крайне редко.


Тем не менее примеры у тебя какие то мутные.

E> А ваше с Владом непонимание, вероятно, вызвано тем, что мы по жизни работаем в разных прикладных направлениях.


Скорее никто не знаком с той кухней, в которой ты варишься. Ну так корректируй свои примеры, учитывая что ты в форум пишешь.

E>Вот, что я имел в виду:


Вроде стало понятнее. Непонятно другое — нафига тут вобще указатели на методы? Свитч из established ты с таким же успехом мог перетащить в process_outgoing. Разница в производительности на сегодняшних процессорах мизерная. Кроме того, идея смешивать основной функционал обработки протокола и проверку версий не очень разумна, проверку надо выносить в отдельный класс. Еще сильно нехорошо что на каждую версию заводится отдельный метод — получается что при смене версий приходится править кучу кода. Наконец, из приведенного кода совершенно непонятна политика управлением временем жизни объектов-наследников pdu_t.

E>Если этот пункт статический (не появляется в произвольный момент), то в одном -- там где меню формируется.

E>Или ты имел в виду и обработчик события так же?

Ага.

E> Если с обработчиком события -- то в двух, естественно.


Вот. А в моем варианте в одном.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[28]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 14:05
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

E>>Вот, что я имел в виду:


AVK>Вроде стало понятнее. Непонятно другое — нафига тут вобще указатели на методы? Свитч из established ты с таким же успехом мог перетащить в process_outgoing.


А затем писать такой же в process_incoming? И вообще в любом месте, где нужно обедиться в корректности PDU.

AVK>Кроме того, идея смешивать основной функционал обработки протокола и проверку версий не очень разумна, проверку надо выносить в отдельный класс.


Правда? Объект pdu -- это просто инкапсуляция сообщения. В нем нет никакой другой функциональности кроме setter-ов/getter-ов и сериализации/десериализации. Имхо, как раз самое то туда и проверку корректности поместить -- каждое сообщение знает, как себя проверять.

AVK>Еще сильно нехорошо что на каждую версию заводится отдельный метод — получается что при смене версий приходится править кучу кода.


Это почему? Выходит новая версия -- добавляется новый метод. Старая-то функциональность остается.

AVK> Наконец, из приведенного кода совершенно непонятна политика управлением временем жизни объектов-наследников pdu_t.


А это тут совсем к делу не относится. Метод process_outgoing получает константную ссылку на объект. Следовательно, ему гарантируют, что на время работы метода эта ссылка будет корректной.

Так а где же пример на динамических делегатах?

E>> Если с обработчиком события -- то в двух, естественно.


AVK>Вот. А в моем варианте в одном.


А как в твоем подходе динамически добавлять/удалять элементы меню?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[29]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 14:18
Оценка: :)
Здравствуйте, eao197, Вы писали:

AVK>>Вроде стало понятнее. Непонятно другое — нафига тут вобще указатели на методы? Свитч из established ты с таким же успехом мог перетащить в process_outgoing.


E>А затем писать такой же в process_incoming? И вообще в любом месте, где нужно обедиться в корректности PDU.


А вот там как раз можно использовать делегат в качестве параметра метода, который внутри себя этот свитч содержит.

AVK>>Еще сильно нехорошо что на каждую версию заводится отдельный метод — получается что при смене версий приходится править кучу кода.


E>Это почему? Выходит новая версия -- добавляется новый метод.


Во все наследники. Масса работы.

E>Так а где же пример на динамических делегатах?


Его бессмысленно делать.

AVK>>Вот. А в моем варианте в одном.


E>А как в твоем подходе динамически добавлять/удалять элементы меню?


В декларации можно указать ключ, а по этому ключу получить ссылку на элемент меню.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[30]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 14:28
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, eao197, Вы писали:


AVK>>>Вроде стало понятнее. Непонятно другое — нафига тут вобще указатели на методы? Свитч из established ты с таким же успехом мог перетащить в process_outgoing.


E>>А затем писать такой же в process_incoming? И вообще в любом месте, где нужно обедиться в корректности PDU.


AVK>А вот там как раз можно использовать делегат в качестве параметра метода, который внутри себя этот свитч содержит.


А тоже самое в коде можно выразить? А то я уже ничего не понял.

AVK>>>Еще сильно нехорошо что на каждую версию заводится отдельный метод — получается что при смене версий приходится править кучу кода.


E>>Это почему? Выходит новая версия -- добавляется новый метод.


AVK>Во все наследники. Масса работы.


Так ведь все сообщения все равно проверять придется. Будет этот метод членом класса или отдельным классом checker-ом.

E>>Так а где же пример на динамических делегатах?


AVK>Его бессмысленно делать.



Бесполезно -- это значит невозможно или что-то другое?

AVK>>>Вот. А в моем варианте в одном.


E>>А как в твоем подходе динамически добавлять/удалять элементы меню?


AVK>В декларации можно указать ключ, а по этому ключу получить ссылку на элемент меню.


И что дальше?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[31]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 14:50
Оценка: :))
Здравствуйте, eao197, Вы писали:

AVK>>А вот там как раз можно использовать делегат в качестве параметра метода, который внутри себя этот свитч содержит.


E>А тоже самое в коде можно выразить? А то я уже ничего не понял.


Я и сам не понял. Сегодня у меня уже что то башка не варит.

AVK>>Во все наследники. Масса работы.


E>Так ведь все сообщения все равно проверять придется. Будет этот метод членом класса или отдельным классом checker-ом.


Так не обязательно проверки в разных версиях различаются. Для кого то нужно писать новую версию, для кого то нет.

E>>>Так а где же пример на динамических делегатах?


AVK>>Его бессмысленно делать.


E>

E>Бесполезно -- это значит невозможно или что-то другое?

Это значит что осмысленности в коде будет 0.

AVK>>В декларации можно указать ключ, а по этому ключу получить ссылку на элемент меню.


E>И что дальше?


А дальше либо в императивном стиле, как ты привел, либо мержить две разные декларации.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[26]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 14:50
Оценка:
Паша, а можно узнать что ты такого забавного в моем сообщении нашел? Посмеемся вместе.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[32]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 15:00
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

AVK>>>Во все наследники. Масса работы.


E>>Так ведь все сообщения все равно проверять придется. Будет этот метод членом класса или отдельным классом checker-ом.


AVK>Так не обязательно проверки в разных версиях различаются. Для кого то нужно писать новую версию, для кого то нет.


Так ведь тогда можно просто предыдущий метод вызвать. Например, из check_ver_5_0 вызвать check_ver_3_4.
А то, что если в базовом классе определить новый чистый виртуальный метод check_ver_n -- это даже хорошо. По крайней мере это заставит просмотреть заново все PDU.
Ну а если совсем уж для ленивых, то в pdu_t можно сделать такой фокус:
void pdu_t::check_ver_5_0() { check_ver_3_4(); }



Так как же в C# сделать делегат, который должен вызывать нестатический метод объекта, но при этом не связан с конкретным объектом?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[33]: Функциональные типы (параллельная ветка)
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 28.06.05 15:11
Оценка:
Здравствуйте, eao197, Вы писали:

E>Так ведь тогда можно просто предыдущий метод вызвать.


Можно, но это лишний пустой код.

E>Так как же в C# сделать делегат, который должен вызывать нестатический метод объекта, но при этом не связан с конкретным объектом?


А я такого никогда не обещал.
... << RSDN@Home 1.2.0 alpha rev. 502>>
AVK Blog
Re[34]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 15:20
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, eao197, Вы писали:


E>>Так ведь тогда можно просто предыдущий метод вызвать.


AVK>Можно, но это лишний пустой код.


Но ты же сам несколькими постами выше говорил, что на современных процессорах это не играет никакой роли

E>>Так как же в C# сделать делегат, который должен вызывать нестатический метод объекта, но при этом не связан с конкретным объектом?


AVK>А я такого никогда не обещал.


Тогда как мне интерпритировать вот это (Re[19]: Has C# lost its point?
Автор: AndrewVK
Дата: 28.06.05
):

E>И спрашивается: какой подход является более общим? Имхо, C++ный. Т.к. функциональность делегата (указатель на метод + указатель на объект) мы можем очень просто сделать. И при этом имеем возможность работать с указателями на методы, не привязанными к конкретным объектам (где-то я такое использовал, при острой необходимости могу поискать). А вот от делегата таких возможностей мы вряд ли дождемся.

О, мне нравится твой подход. Буквально абзацем выше ты фактически признался в том что нечетко представляешь, что такое делегат, а уже сделал вывод что в делегате каких то возможностей нет, и, хуже того, что мы их не дождемся.


Мне интересно, возможно ли с делегатами C# то, что выделено жирным? И если не возможно, то как тогда твое возражение понимать?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[27]: Функциональные типы (параллельная ветка)
От: Павел Кузнецов  
Дата: 28.06.05 18:53
Оценка: +1 -1
AndrewVK,

> Паша, а можно узнать что ты такого забавного в моем сообщении нашел? Посмеемся вместе.


Оценку "" ставлю, когда мне в результате прочтения сообщения смешно.

В данном случае: для C++ есть только ISO стандарт. Соответственно, ответ на этот вопрос получается в первых же результатах любого запроса в Google, содержащего слова "C++" и "Standard". А если искать именно по поводу вопроса "есть ли ISO стандарт для C++", т.е. включив слово "ISO" в запрос, то ссылки на ISO стандарт будут в каждом из результатов, по крайней мере, на первой странице.

Мне факт задания вопроса в форум вместо единственного запроса к Google показался удивительным и смешным
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[18]: Функциональные типы (параллельная ветка)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 28.06.05 20:17
Оценка: 70 (4) +1
Здравствуйте, VladD2, Вы писали:

VD>>>Какое отношение этот рассказ имеет к вопросу? Повторю еще раз цитаты:

VD>>>>>>Да, не понимаю. Сборка это набор байт. Всегда можно скачать...

E>>>>>Нет. Далеко не всегда.


VD>>>>И когда нельзя?

VD>>>>Раскрывай.

E>>Влад, вот ты часто говоришь, что занимаешься интеропом. Но ты представляешь себе реальные прикладные протоколы, которые используются для организации взаимодействия нескольких удаленных машин? Вот скажем обмениваются информацией о транзакциях два банковких сервера. Или несколько машин в кластере обмениваются результатами вычислений. Или даже когда браузер обращается к web-серверу за страничкой. Все они ожидают получить данные, именно данные, а не код, который эти данные может распарсить. И проблемы начинаются, когда версия данных на одной стороне начинает разсогласовываться с тем, что ожидает другая сторона.


VD>Ясно. Прямого ответа на вопрос я не получу. Ну, да понятно почему...


Почему? Просвети меня, а то я в полном непонимании нахожусь.

E>>А вот в Asn1 было введено понятие "extension points" -- это такие места в спецификации протокола, где говорится -- вот в этом месте в будущем может что-то появиться.


VD>Очень смахивает на введение лишних параметров на всякий случай. Мне кажется это очень не верное решение. Лучше не пытаться угадать что будет в будущем, а просто позволить читать информацию о том, что есть в настоящем.


Влад, ты можешь сколь угодно много и долго сомневаться и иронизировать по поводу моей компетенции, но Abstract Syntax Notation One -- это очень серьезная штука, которая развивается уже почти двадцать лет. И стандарт Asn1 прошел уже несколько ревизий. Так что случайные или не нужные вещи там еще поискать нужно. И extension points -- это одно из ключевых понятий в Asn1.

Кроме того, не нужно понимать extension points как примитивные поля dwReserved1, dwReserved2, etc. Это очень полезный и нужный механизм, имеющий очень маленький overhead (в кодировках BER и PER). А введены extension points как раз для того, чтобы не пытаться угадать, что будет в будущем. Достаточно просто указать, что тип допускает расширения в будущем. А когда эти расширения потребуются -- просто сделать их. И при всем этом обеспечивается прозачная интероперабильность с предыдущими версиями спецификации.

E>>Вот я и спрашивал, поддерживает ли BinaryFormatter в .Net подобные фишки. И все мои примеры как раз были об этом.


VD>У тебя есть некоторое представление о том, ка должен быть реализован BinaryFormatter если для его реализации использовать С++ и привычные тебе идиомы/паттерны. Но это не вереный подход. Для понимания того что такое BinaryFormatter и как он устроен нужно понять идиомы и паттерны дотнета и отказаться от взгляда на мир с точки зрения С++.


VD>В общем, проще говорить о возможностях. Сформулируй какие возможности ты хотел бы видеть от BinaryFormatter и я тебе скажу реализованы ли они или нет.


1. Можно ли избежать сериализации полей, которые имеют значения по умолчанию?

2. Допустим, структура A (я пользуюсь C++ синтаксисом) сначала имела вид:
struct    A
    {
        int    m_a;
        std::string m_s;
    };

ее сериализовали в двоичный файл. Затем структуру расширили:
struct    A
    {
        int    m_a;
        std::string m_s;
        double m_d;
    };

и попытались десериализовать этот двоичный файл, что получится?

E>>Потому что конкретный прикладной протокол придется заморачивать не только на передачу прикладных данных, но и на передачу кода.


VD>Это можно сделать введя очень простенький компонент. В его задачи будет входить контроль наличия сборки (что в дотнете делается простым подключением на специальное событие) и подкачку нужной сборки если сборки еще нет.


VD>Безусловно это дополнительный код, но к протоколу он отношения не имеет. Ну, и не так уж он и сложен.


Влад, ты когда нибудь видел спецификации телекомуникационных протоколов? Например, SMPP или какого-нибудь GSM протокола? Как ты думаешь, куда там можно вставить обмен кодом?

E>>Вот именно. Но я говорю о случаях, когда сериализация/десериализация на разных сторонах делается по разным версиям описания схемы данных.


VD>Звучит не разумно.


Тем не менее, такое со временем случается. Даже, afaik, носит название "проблемы второй версии протокола". Особенно актуально это для двоичных протоколов (и здесь рулят Asn1 с его extension points), хотя и со структурированными текстовыми (XML в частности) такие вещи случаются.

Вот например, реализовали сервис по доставке уведомлений клиенту о каком-то событии (скажем, закончились продукты в холодильнике или сработала сигнализация в его квартире). В первой версии протокола в запросе send_message реализовали поддержку уведомлений о доставке сообщения. Т.е. сначала идет send_message на что сервер отвечает send_message_ack (если он взялся за доставку) или send_message_nack (если доставка по каким-то причинам невозможна). А когда клиент подтверждает прочтение сообщения, сервер присылает уведомление message_status_notification:
client                                   server
======                                   ======
  |  ---- send_message ----------------->  |
  | <---- send_message_ack --------------  |
  | <---- message_status_notification ---  |
  | - message_status_notification_ack -->  |


Поработал такой сервис год-два, подключили к нему сотню-другую крупных клиентов и пришло время делать обновленную версию. Например, указывать, чтобы message_status_notification приходил не всегда, а только, если подтверждения от клиента не было в течении определенного времени (чтобы если клиент не реагирует на сигнализацию в течении 15-ти минут можно было принять какие-то другие действия). И нужно сделать так, чтобы сервер, если на доставка message_status_notification завершилась неудачно, попробовал доставить message_status_notification на другой адрес. Фантазировать здесь можно сколько угодно -- практика показывает, что во вторую версию протокола пытаются запихнуть больше функциональности, чем реально необходимо.

Так вот встает вопрос, как в send_message передавать расширенную информацию о message_status_notification?

Можно, конечно, добавить send_message_ex с другим синтаксисом. Но тогда может потребоваться модификация промежуточного ПО. Например, файрволов, спам-фильтров или статистических анализаторов. А можно, если позволяет технология сериализации send_message, просто добавить еще одно поле ext_status_notification, которое будут анализировать и обрабатывать только те, кто про него знают.

Есть общераспространненые способы решения таких задач. Для бинарных протоколов:
— механизм Tag-Length-Value (TLV или же, по научному, Asn1 Basic Encoding Rules -- BER). Все поля имеют обязательные поля Tag и Length. Поля с неизвестным значением Tag просто пропускаются.
— механизм extension points -- специальных меток, которые указывают, есть ли расширения. Применяется в Asn1 Packed Encoding Rules (PER). Представляется одним битом. Если раширение есть, то за этим битом следует длина расширения, а затем содержимое расширения. Естественно, что взаимодействующие стороны должны договорится о точных местах extension points, но обычно это не проблема, т.к. все начинают с общей спецификации. Аналогичный подход применяется и у меня.

Для текстовых протоколов:
— в случае с протоколами типа http новые поля добавляются в виде дополнительных http-заголовков с новыми именами;
— в случае XML (SOAP или Visa 3D Secure) определяются специальные теги, работающие как extension points. Заранее обговаривается, что протокол может быть расширен в специальном теге, скажем, <extension>. Если кто-то не в состоянии интерпритировать содержимое <extension>, он должен его пропускать. В SOAP, afaik, такая штука была даже специфицирована со специальным атрибутом mustUnderstand, который указывает, имеет ли право сторона, которая не знает про расширение, обрабатывать весь запрос.

Не берусь точто утверждать, но, имхо, XML-протоколы со специальными тегами-расширениями, не поддерживают DTD. Да и ручной парсинг и последующая перегенерация такого XML являетя не простой задачей.

Ручной парсинг как двоичного формата с расширениями, так и XML-формата, является муторным и неблагодарным занятием. Именно поэтому для Asn1 рекомендуют использовать asn1-компиляторы (которые стоят ну оОочень не дешево). Но они того стоят -- ручная работа с Asn1 PER (да еще с нормальной битовой упаковкой) -- это та еще работа.
Вот я и сделал в своем инструменте автоматическую поддержку подобных расширений. И мне интересно, существует ли такая поддержка в .Net-сериализаторах. В частности, в бинарном сериализаторе.

VD>>> Ну, и всегда можно сделать простенькое решение которое сможет копировать нужные интерфесные сборки в автомате. Итго — это не языковая проблема. Это проблема дизайна.


E>>Именно дизайна. И попытаться решить нетривиальную проблему дизайна простенькими средствами языка может быть слишком сложно.


VD>Ты погряз в догмах и проблемах С++. То что ты называшь "нетривиальной проблемой дизайна" на самом деле является обычной пробемой дизайна довольно не сложно решаемой в компонентных средах.


Я сейчас говорю не про технологии программирования, а о проблемах прикладных протоколов. И о некоторых способах их преодоления.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Функциональные типы (параллельная ветка)
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.06.05 23:46
Оценка: :)
Здравствуйте, eao197, Вы писали:

E>Имхо, суть указателя на метод именно в том, что это указатель на метод. Который можно применить к любому объекту этого типа (и к любому объекту производного типа).


Ага. А по жизни требуется применять его к любому объекту любого типа у которого есть метод с нужной сигнатурой.

E> Делегат же, насколько я понял из твоих объяснений, это тот же указатель, который намертво связан с конкретным объектом. Поэтому применить делегат к другому объекту этого же типа уже не реально (правильно?).


Делегат — это ссылочный тип. Переменная типа делегат может указывать на любыее методы любых объектов. Так что функционально ты ничем не связан. Делегат же можно рассматривать как указатель на метод. Причем не только на метод эеземпляра. Он точно так же может указывать и на статический метод.

E>И спрашивается: какой подход является более общим?


Тот с который позволяет решить большее количество задач большим количеством способов. То есть делегат.

E> Имхо, C++ный.


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

E> Т.к. функциональность делегата (указатель на метод + указатель на объект) мы можем очень просто сделать.


Языком если только. Не уверен, что лично ты справишся если не заглядывал в тот же сигнал.

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

E> И при этом имеем возможность работать с указателями на методы, не привязанными к конкретным объектам (где-то я такое использовал, при острой необходимости могу поискать). А вот от делегата таких возможностей мы вряд ли дождемся.


Забавно. Ты только что смотрел пример где не только динамически привязывался экземпляр объекта, но и динамически же привязывался метод. Хрена два ты такое на современном С++ сделашь. Но тем не менее пыташся делать выводы об ущербности делегатов.

E>Ничего принципиально другого, кроме синтаксиса, по сравнению со своим примером я не увидел.


А должно был быть другое? Я реализовал твой пример. Другое будет когда ты захочишь ссылаться на внешние методы разных классов.

VD>>Так вот, твой случай частный, так как ссылка нужна в рамках класса. И как частный случай он легко реализуется на делегатах. Но твой случай можно усложнить введя требование возможности передачи управления в любой объект, ане только этот же или даже в объекты этого же типа. И тут делегаты опять таки дают чистое и красивое решение, а указатели на методы класса пасуют.


E>Это как же указатели на методы пасуют?


Так же. Не позволяют ссылаться на метод по сигнатуре тем самым ограничивая тебя экземплярами одного объекта.

Не ужели не видно, что выдаваемая тобой и ПК "универсальная и более общая абстракция" позволяет решать катастрафически узкий класс задач. А делегаты более широкий, хотя вы и пытаетесь сделать вид, что они не универсальны и вооще фигня на послом масле.

VD>>Проблема тут в черезмерной заботе о контроле типов. Страуструпу показалось, что если дать программистам возможность вызыать любой метод с некоторой сигнатурой, то появится куча ошибок. Но это ложное предположение.


E>И чем же ты это предположение опровергаешь?


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

VD>>Все что нужно сделать, это убрать этот лишний контроль.


E>А вот это от тебя по отношению к C++ вообще странно слышать: то тебе контроля со стороны C++ мало, а тут -- убрать лишний контроль нафиг! Так чему верить-то?


Странно наклеивать на всех ярлыки. Ошибок типизации отказ от этой протухшей догмы не создает. За то позволяет применять указатели на методы значительно чаще и эффективнее. При этом нет необходимости городить море метакода чтобы обойти дурацкое ограничение.

E>Влад, я уже давно не программировал на WinAPI, но даже в низопамятные времена получать в обработчик сообщения голый Message, а затем извлекать из wParam, lParam нужные значения было каменным веком. Даже если не брать обработчиков сообщений в MFC, то были замечательные макросы из windowsx.h. Поэтому приведенный здесь фрагмент может быть и выглядит красивым с точки зрения использования атрибутов .Net, но я бы хотел работать с обработчиками сообщений вида:

E>
E>void    OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
E>void    OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
E>void    OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
E>

E>и т.д.

Причем тут сигнатуры? Елы-палы, ну, ты вдумывайся в слова то.
Я тебе показал, как используя ссылки на внешние методы можно довести программирование до декларативного вида, т.е. написать универсальный класс хранящий ссылки на внешние методы другого класса. Тут даже атрибуты не очень причем. Они просто "клей", дополнительная метаифномация позволяющая связать методы с событием.

А что до обработчиков... Да в ВыньФормсах их довно обернули так, что твои С++-ные изыски покажутся детскими поделками. К сожалению, это оборачивание автоматизировать нельзя. Нет в ВыньАпи метаданных которые можно было бы разобрать программно. Были бы, то и обертывание моно было бы автоматизировать.

E>Не вижу в этом коде ничего выдающегося.


Создай анлог на С++ и поймешь, что в нем выдающегося... когда сравнишь объем и кривость получившегося решения.

E> Подобные решения на C++ существовали еще за десять лет до появления C#.


Нет подобных решений на С++. На С++ подобный код превращается в закат солнца вручную. И проще бывает смастерить какие-нибудь мап-ы на макросах или шаблонах. Поддерживать такой код не удобно. Создавать медленно. Обвязочного кода горы.

E>Конечно, в C++ для него потребовалось бы вручную поддерживать таблицу имен функций и соответствующие им имена.


Блин, а зачем вообще этот код если нужно создавать какие-то таблицы? Тогда уж создавай мап и трахайся с его заплнением.

Еще раз, это решение опять же демонстриует приемущество делегатов которые будучи размещенными в одном классе ссылаются на методы другого позвляя тем самым довести выбор метода обработчика до примитивного выбора из ассоциативного массива. Ну, а их динамическая природа позволяет вообще обходиться без программирования при добавлении новых методов обработчиков.

E> В C# это делается автоматом при помощи рефлекшена. Удобно?


Еще как! Но смысл примера в данном случае был не в этом.

E> На первый взгляд, может быть.


И на 255-ый тоже. Если конечно не придумывать пробем специально.

E> Но чем за это платить приходится?


Отказом от старых догм и предрассудков.

E> У меня в программах сотни типов и только для очень малой их части нужна информация для рефлекшена.


У тебя море кода который неподемен по причине постоянной потребности долбления импиративного кода. Это же декларативное решение. В нем просто нет программирования. Описываешь клавиатурное соокрщение и имя метода обработчика. Все! Никаких ошибок, никакой отладки. И все это ассоциируется при загрузке программы не требуя перекомпиляции. При этом никакой возни с идентификаторами и т.п.

E> Поэтому я вполне в состоянии эту информацию предоставить сам.


У меня написание этого класса с отладкой и тестированием заняло около часа, ну может двух. Если ты действительно уверен что все так просто, создай аналогичный код для плюсов и сравним объем и красоту решения. За одно поможешь менее квалифицированным коллегам набраться опыта.

E> Кроме того, вот что ты будешь делать, если тебе потребуется имя метода CaretVirtualLineUp переименовать? Будешь править все конфиги? А что, если для имени "CaretVirtualLineUp" тебе потребуется либо подставлять метод CaretVirtualLineUpClassic, либо метод CaretVirtualLineUpWrappedView, или CaretVirtualLineUpRestructedView в зависимости от других настроек? Где тогда рефлекшен окажется?


Вот, кстати, спасибо. Я лохонулся. В начале работы над редактором назвал строки в представлении (view) Virtual, а строки в документе Real. Когда начал описывать редактор в статье, понял что это не интуитивно и решил изменить развания на View и Document соотвественно. Причем имена типов переименовал, проверить другие имена забыл. Так что действительно методы нужно переназвать. Вот как раз прочтя твое сообщение это и сделал. Заняло это занятие меньше минуты. Просто взял и заменил по контексту "CaretVirtual{:i+}" на "CaretView\1" (с включенными регекспами). Заняло это занятие времени меньше чем писал этот абзац (значительно меньше). Что? А если имя не так уникально? А, ну, не беда. Тода прийдется заменить его у метода (средствами рефакторинга), а потом ручками в ХМЛ-файле. Если забуду, то код:
catch (Exception ex)
{
    errors.AppendLine("Can't add key '" + key + "' with action '"
        + action + "'. " + ex.Message);
}

при запуске выдаст мне список ошибок.

E>Влад, я что-то не понял, а почему XML вручную читается?


Ну, уж не совсем вручную. Я не маньяк еще парсить ХМЛ руками.

E> А где же хваленая прозрачная XML сериализация? Где XSD, которая бы позволила проверять семантическую корректность?


Схему подключить можно, но для данной задачи не очень то и нужно. А читаю вручню по совсем банальной причине. Не хочу тормозить загрузку компонента. Код сканирования даже на таком низком уровне занимает несколько строк:
if (!reader.Read() || reader.Name != "xml")
    throw new ApplicationException("Неверный формат файла KeyboardShortcutsMap.xml");

while (reader.Read() && string.IsNullOrEmpty(reader.Name))
    ;

if (reader.Name != "Shortcuts")
    throw new ApplicationException("Неверный формат файла KeyboardShortcutsMap.xml");
...
key = reader.GetAttribute("Key"); // читаем ключь
// читаем имя делегата
action = reader.GetAttribute("Action");

Конечно можно было бы заменить их на использование TataSet или XPath, но игра не стоит свечь. Было бы на две строки меньше и в 10 раз медленее. Может оно и не было бы заметно на современных машинах, да и выполняется чтение всего один раз на загрузку, но так как разница всего две строки, я вибрал более быстрое решение. XmlReader — это очень быстро.

E>И что будет, если в атрибуте Key задать, например: "Control | Alt | Control | Alt | Control"?


Будет булево или.
/// <summary>
/// Преобразует строку содержащую имена клавишь в Keys.
/// Имена клавишь могут объеденяться по или (знаком "|").
/// </summary>
/// <example>"Shift | Control | Right"</example>
/// <param name="key">Клавиатурное сокращение в виде строки.</param>
private static Keys ParseKeys(string key)
{
    Keys keys;
    // Разбиваем ключь на отдельные значения
    string[] keyStrs = key.Split('|');
    keys = 0;

    foreach (string value in keyStrs)
        keys |= (Keys)Enum.Parse(typeof(Keys), value);
    return keys;
}


Если не ясно могу по шагам разобрать:
    // Enum в который нужно получить фалги.
    Keys keys = 0;
    
    // Разбиваем ключь на отдельные значения. Разделитель '|'.
    // В результате keyStrs содержит по одному элементу для каждого
    // значения разделенного знаком '|' (возможно с пробелами).
    string[] keyStrs = key.Split('|');

    // Перебираем все значения из keyStrs 
    foreach (string value in keyStrs)
        // и каждое из них пытаемся распарсить встроенной в дотнет-ные
        // enum-ы функцией Enum.Parse(). Она пропускает пробелы, но 
        // учитывает регистр.
        // Если при парсинге возникает сбой, то генерируется исключение,
        // которое обрабатывается на более высоком уровне.
        // Результат парсинга складывается "по или" 
        keys |= (Keys)Enum.Parse(typeof(Keys), value);
        
    return keys;



E>В моем подходе к парсингу конфигов класс для разбора одного Shortcat-a выглядел бы так:

E>
E>using namespace cls_2;

E>class    tag_shortcat_t : public tag_no_value_t
E>    {
E>    private :
E>        tag_scalar_t< std::string >    m_key;
E>        tag_scalar_t< std::string >    m_action;
E>        tag_no_value_t    m_ctrl;
E>        tag_no_value_t    m_alt;
E>        tag_no_value_t    m_shift;
E>    public :
E>        // Формат конструктора диктуется требованиями класса tag_vector_of_tags_t.
E>        tag_shortcat_t( const char * name, bool is_mandatory )
E>            :    tag_no_value_t( name, is_mandatory, true )
E>            ,    m_key( self_tag(), "key", true )
E>            ,    m_action( self_tag(), "action", true )
E>            ,    m_ctrl( m_key, "ctrl", false )
E>            ,    m_alt( m_key, "alt", false )
E>            ,    m_shift( m_key, "shift", false )
E>            {}
            
E>        // Код метода по извлечению значений из m_key, m_action, m_ctrl, m_alt и m_shift по вкусу :)
E>        shortcat_t query_value() const
E>        {
E>            return shortcat_t( m_key.query_value(), m_action.query_value(),
E>                ( m_ctrl.is_defined() ? VK_CTRL : 0 ) |
E>                ( m_alt.is_defined() ? VK_ALT : 0 ) |
E>                ( m_shift.is_defined() ? VK_SHIFT : 0 ) );
E>        }
E>    };
E>


Да что уж скромничать. Ты создай полный код делающий тоже что и мой. Вот тогда и сравним. А за одно предложим общественности сравнить понятность и простоту форматов.

E>И такой класс позволил бы разбирать конфиги вида:

E>
E>|| Навигация по тексту
E>{shortcat {key "Up"}                    {action "CaretVirtualLineUp"}}
E>{shortcat {key "Down"}                  {action "CaretVirtualLineDown"}}
E>{shortcat {key {shirt} "Up"}            {action "CaretVirtualLineUpExtend"}}
E>{shortcat {key {shift} "Down"}          {action "CaretVirtualLineDownExtend"}}
E>{shortcat {key "Home"}                  {action "CaretVirtualLineHome"}}
E>{shortcat {key "End"}                   {action "CaretVirtualLineEnd"}}
E>{shortcat {key {shift} "Home"}          {action "CaretVirtualLineHomeExtend"}}
E>{shortcat {key {shift} "End"}           {action "CaretVirtualLineEndExtend"}}
E>{shortcat {key "Left"}                  {action "CaretLeft"}}
E>{shortcat {key {ctrl} "Left"}           {action "CaretWordLeft"}}
E>{shortcat {key {ctrl} "Right"}          {action "CaretWordRight"}}
E>{shortcat {key {shirt} {ctrl} "Left"}   {action "CaretWordLeftExtend"}}
E>...
E>|| Клипборд
E>{shortcat {key {ctrl}  "C"}             {action "Copy"}}
E>{shortcat {key {ctrl}  "Insert"}        {action "Copy"}}
E>{shortcat {key {ctrl}  "V"}             {action "Paste"}}
E>{shortcat {key {shift} "Insert"}        {action "Paste"}}
E>{shortcat {key {ctrl}  "X"}             {action "Cut"}}
E>{shortcat {key {shift} "Delete"}        {action "Cut"}}
E>


Кстати, мне ХМЛ-ный вариант нравится куда болье. Читается лучше. К тому же мой формат можно очень удобно редактировать в редакторе с подсветкой синтаксиса и в считанные минуты прикрутить к нему ГУИ-редактирование. И все это без создания каких-то фрэймворков. Так сказать на пустом месте.

E>При этом код по извлечению значений из конфига будет работать только с именем типа tag_shortcat_t и его методом query_value().


Если скорось не очень важна, то код парсинга можно было бы довести до вот такого:
DataSet shortcutsDataSet = new DataSet();
shortcutsDataSet.ReadXml(OpenReader());
DataTable shortcutsTable = shortcutsDataSet.Tables["Shortcuts"];

foreach (DataRow row in shortcutsTable.Rows)
{
    string key = (string)row["Key"];
    string action = (string)row["Action"];
    ...
}

Как я уже говорил раньше, на этом бы я выиграл несколько строк кода, но проиграл бы в производительности за счет того что DataSet занимается распознованием данных в ХМЛ-е и загружает данные в память (в свой формат).

E> И поэтому не будет привязан ни к конкретным именам тегов, ни к конкретной реализации самого тега (например, можно прозрачным образом ввести псевдонимы для ctrl, alt, shift. Или даже сменить формат shortcat-а на такой:

E>
E>{shortcat
E>        {key {ctrl}  "C"}
E>        {key {ctrl}  "Insert"}
E>    {action "Copy"}}
E>{shortcat
E>        {key {ctrl}  "V"}
E>        {key {shift} "Insert"}
E>    {action "Paste"}}
E>{shortcat
E>        {key {ctrl}  "X"}
E>        {key {shift} "Delete"}
E>    {action "Cut"}}
E>


Зачем?

E>Так что по объему мой велосипедный подход не сильно больше твоего, а вот в сопровождении, имхо, мой удобнее.


По объему твой вилосипед уже больше чем мой код. А если его довести до работоспособности, то он будет намного больше. Ну, и главное, решение на С++ и рядом не будет сотять по простоте и красоте. А пользователь получит малопонятный формат который еще прийдется изучать.

E>Я, напротив, думаю, что это пример того, как используя небольшой набор языковых возможностей получить более высокоуровневые средства. А вот в C# для этого пришлось язык расширять.


Расширять? Делегаты часть языка. Не большеая, кстати, чем указатели на методы. Только куда более продуманная, удобная и гибкая. Единственный их недостаток, они не так быстры как С-шные указатели на функции. Но и это уже во втором фрэймворке пофисили.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.