Здравствуйте, eao197, Вы писали:
E>Мало уступает, да?
На то есть разные мнения. Есть, напрмер, мнение что малость превосходит. А есть, что сильно...
E>А как тогда на C# сделать такое: А generic-и так могут?
АВК тебе уже сказал в чем проблема твоего вопроса. Могу повторить еще раз. Изучать тонкости твоих проблем и вникать в горы кода никто не хочет.
Скорее всего твои проблемы связанны с тем, что ты хочешь решать задачи на C# так же как если бы ты решал их на С++. Но это другой язык. Программирование на нем — это классическое ООП + компонентное проеграммирование. Если не задаваться целью решать задачи так же как на С++, то обычно, задачи решаются значительно поще и быстрее.
или как сделать сериализацию на С++ такой же простой как в дотнете.
МС++, о котором иедт речь в данном эссе, это конечно не С++. Это анаптация С++ к дотнету. Разница между ним и Шарпом уже не критична, так как все они позволяют использовать мошь дотнета. Так что о нем разговор особый.
VD>АВК тебе уже сказал в чем проблема твоего вопроса. Могу повторить еще раз. Изучать тонкости твоих проблем и вникать в горы кода никто не хочет.
А так всегда -- на словах все мудрецы и монстры. А как до реальных решений доходит, то "твои проблемы", "горы кода".
Я помниться когда-то спросил, почему Янус на C++ не был написан. Так я стал сразу одним из тех самых умных, которые никогда ничего не делают. А здесь реальная проблема, которая на C++ решилась без труда и могла бы быть решена еще проще. Но стоило всего лишь поинтересоваться, как ее решить средствами generic-ов, как C#-евангелисты отмазки начали приводить. Здорово (еще бы, это не C# c Python-ом в разработке игр применять). Только проблема в том, что я и так привел минимальный реальный код. В дейсвительности там еще больше навороты на более высоких уровнях есть. И на C++ это все работает и является сопровождаемым.
VD>Скорее всего твои проблемы связанны с тем, что ты хочешь решать задачи на C# так же как если бы ты решал их на С++.
Я не хочу решать задачи на C#. Мне просто интересно, как это могло бы быть.
VD>Если ты действительно хочешь что-то сравнить, то порпробуй ответить на вопрос как на С++ сделать вот это: http://rsdn.ru/article/dotnet/dnetappcfg.xml
или как сделать сериализацию на С++ такой же простой как в дотнете.
Ok. Статью посмотрю. Подумаю.
Сериализаций для C++ как собак нерезанных. Сам персонально одной такой занимаюсь -- успешно применяется в production code уже около 2-х лет и нет проблем.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Если ты действительно хочешь что-то сравнить, то порпробуй ответить на вопрос как на С++ сделать вот это: http://rsdn.ru/article/dotnet/dnetappcfg.xml
или как сделать сериализацию на С++ такой же простой как в дотнете.
Посмотрел, увидел теже самые тоны кода. Подумал, не понял что должен был ответить.
Ну сделали вы для C# удобное решение с использованием встроенной в платформу поддержки XML сериализации и атрибутами (или как они в .Net-е называются). И что, это должно было продемонстрировать преимущества C# над C++? Ok. Если ты в этом уверен, то пусть в данной конкреной области будет так.
Алаверды привожу код на C++ для парсинга конфигов следующего вида:
Реализуется эта кухня следующим образом. Вот описания структур для хранения информации:
//! Коды операций над значениями источников данных.enum op_codes_t {
//! ==
op_equal,
//! !=
op_not_equal,
//! <
op_less,
//! <=
op_less_equal,
//! >
op_greater,
//! >=
op_greater_equal,
//! Неизвестный код операции.
op_invalid
};
//! Получить код операции по строковому начертанию.inline op_codes_t
op_code( const std::string & o )
{
if( "==" == o ) return op_equal;
if( "!=" == o ) return op_not_equal;
if( "<" == o ) return op_less;
if( "<=" == o ) return op_less_equal;
if( ">" == o ) return op_greater;
if( ">=" == o ) return op_greater_equal;
return op_invalid;
}
//
// if_t
//
//! Описание условия и действий, которые нужно выполнить, если
//! это условие выполняется.template< class T >
struct if_t
{
//! Код операции над значением.
op_codes_t m_op;
//! Правый операнд операции сравнения со значением источника данных.
T m_right;
//! Действия, которые нужно выполнить, если условие выполняется.
actions_t m_actions;
//! Конструктор по умолчанию.
if_t()
: m_op( op_invalid )
{}
//! Инициализирующий конструктор.
if_t(
op_codes_t op,
const T & right,
const actions_t & actions )
: m_op( op )
, m_right( right )
, m_actions( actions )
{}
//! Проверить условие.
/*! \return true, если условие выполняется. */bool
operator()(
//! Значение источника данных.const T & left ) const
{
if( op_equal == m_op ) return ( left == m_right );
if( op_not_equal == m_op ) return ( left != m_right );
if( op_less == m_op ) return ( left < m_right );
if( op_less_equal == m_op ) return ( left <= m_right );
if( op_greater == m_op ) return ( left > m_right );
if( op_greater_equal == m_op ) return ( left >= m_right );
return false;
}
};
//! Коды состояния источников данныхenum data_source_status_t {
//! Источник был зарегистрирован
e_data_source_reg,
//! Источник работает в обычном режиме
e_data_source_work,
//! Источник был дерегистрирован
e_data_source_dereg
};
//
// data_class_t
//
//! Описание класса источника данных.template< class T >
struct data_class_t
{
//! Приоритет источников данных этого класса.
/*! Предположительно, значения в диапазоне 0..9. */unsigned char m_priority;
//! Величина шрифта в пунктах.int m_font_size;
//! Список условий, которые нужно проверять.
std::vector< if_t< T > > m_conditions;
//! Действия, которые нужно выполнить, если ни одно
//! из условий не выполнено.
actions_t m_otherwise;
//! Действия, которые нужно выполнять при регистрации источника данных
actions_t m_on_register;
//! Действия, которые нужно выполнять при дерегистрации источника данных
actions_t m_on_deregister;
//! Конструктор по-умолчанию.
data_class_t()
: m_priority( 0 )
, m_font_size( 0 )
{}
//! Определить, какие действия нужно сделать над
//! данным значением источника данных.
/*!
В \a a помещается описание действий, которые
должны быть выполнены над значением. Если было выполнено
какое-то условие из m_conditions, то возвращаются действия,
назначенные для данного условия. В противном случае
возвращается значение m_otherwise.
\return Номер условия в m_conditions, которое
было выполнено (значение >= 0). -1, если
ни одно из условий в m_conditions не было
выполнено.
*/int
operator()(
//! Значение источника данных.const T & left,
//! Приемник описания действий.
actions_t & a,
//! Текущее состояние источника данных
data_source_status_t status = e_data_source_work ) const
{
switch( status )
{
case e_data_source_work:
for( int i = 0, i_max = (int)m_conditions.size();
i != i_max; ++i )
{
if( m_conditions[ i ]( left ) )
{
a = m_conditions[ i ].m_actions;
return i;
}
}
a = m_otherwise;
return -1;
case e_data_source_reg:
a = m_on_register;
return -2;
case e_data_source_dereg:
a = m_on_deregister;
return -3;
default:
a = m_otherwise;
return -1;
}
}
};
А вот сам парсинг конфигурационного файла:
//
// tag_op_t
//
/*!
Класс тега для разбора типа сравнения и величины для
сравнения.
*/template< class T >
class tag_op_t
: public cls_2::tag_scalar_t< T >
{
//! Псевдоним для базового типа.typedef cls_2::tag_scalar_t< T > base_type_t;
public :
//! Основной конструктор.
tag_op_t( cls_2::tag_t & owner )
: base_type_t( owner, "op", true )
{}
virtual ~tag_op_t()
{}
//! Определить, какой тип операции используется.virtual bool
compare_name( const char * name ) const
{
op_codes_t op = op_code( name );
if( op_invalid != op )
{
m_op = op;
return true;
}
return false;
}
//! Получить значения.void
get( if_t< T > & to ) const
{
to.m_op = m_op;
to.m_right = query_value();
}
private :
//! Тип операции.mutable op_codes_t m_op;
};
//! Заполнить ограничитель значений цветов.void
fill_color_constraint(
cls_2::scalar_constraint::one_of_t< std::string > & c )
{
c.add( "white" );
c.add( "black" );
c.add( "red" );
c.add( "dark_red" );
c.add( "green" );
c.add( "dark_green" );
c.add( "blue" );
c.add( "dark_blue" );
c.add( "cyan" );
c.add( "dark_cyan" );
c.add( "magenta" );
c.add( "dark_magenta" );
c.add( "yellow" );
c.add( "dakr_yellow" );
c.add( "gray" );
c.add( "dark_gray" );
c.add( "light_gray" );
}
//
// tag_if_t
//
/*!
Класс для разбора условий.
*/template< class T >
class tag_if_t
: public cls_2::tag_no_value_t
{
//! Псевдоним для базового типа.typedef cls_2::tag_no_value_t base_type_t;
private :
//! Условие сравнения.
tag_op_t< T > m_op;
//! Имя графического образа.
cls_2::tag_scalar_t< std::string > m_pixmap;
//! Фоновый цвет.
cls_2::tag_scalar_t< std::string > m_bkcolor;
//! Ограничения на значения цветов.
cls_2::scalar_constraint::one_of_t< std::string >
m_bkcolor_constraint;
//! Звуковой файл для воспроизведения.
cls_2::tag_scalar_t< std::string > m_sound;
//! Событие для log_writter.
tag_log_event_t m_log_event;
//! Список внешних приложений для запуска.
cls_2::tag_vector_of_tags_t< tag_launch_external_t >
m_launch_external;
//! Предикат для std::transform.static launch_external_t
launch_external_getter(
const tag_launch_external_t & tag )
{
return tag.get();
}
public :
tag_if_t(
const char * name,
bool is_mandatory )
: base_type_t( name, is_mandatory, true )
, m_op( self_tag() )
, m_pixmap( self_tag(), "pixmap", false )
, m_bkcolor( self_tag(), "bkcolor", false )
, m_sound( self_tag(), "sound", false )
, m_log_event( self_tag(), "log_event", false )
, m_launch_external( self_tag(), "launch_external", false )
{
fill_color_constraint( m_bkcolor_constraint );
m_bkcolor.set_constraint( &m_bkcolor_constraint );
}
virtual ~tag_if_t()
{}
//! Получить значения.
if_t< T >
get() const
{
if_t< T > to;
m_op.get( to );
m_pixmap.query_opt_value( to.m_actions.m_pixmap );
m_bkcolor.query_opt_value( to.m_actions.m_bkcolor );
m_sound.query_opt_value( to.m_actions.m_sound );
if( m_log_event.is_defined() )
to.m_actions.m_log_event = m_log_event.get();
if( m_launch_external.is_defined() )
std::transform( m_launch_external.begin(),
m_launch_external.end(),
std::back_inserter(
to.m_actions.m_launch_external ),
launch_external_getter );
return to;
}
};
//
// tag_otherwise_t
//
/*!
Класс для разбора действий по умолчанию.
*/class tag_otherwise_t
: public cls_2::tag_no_value_t
{
//! Псевдоним для базового типа.typedef cls_2::tag_no_value_t base_type_t;
private :
//! Имя графического образа.
cls_2::tag_scalar_t< std::string > m_pixmap;
//! Фоновый цвет.
cls_2::tag_scalar_t< std::string > m_bkcolor;
//! Ограничения на значения цветов.
cls_2::scalar_constraint::one_of_t< std::string >
m_bkcolor_constraint;
//! Звуковой файл.
cls_2::tag_scalar_t< std::string > m_sound;
//! Событие для log_writter.
tag_log_event_t m_log_event;
//! Список внешних приложений для запуска.
cls_2::tag_vector_of_tags_t< tag_launch_external_t >
m_launch_external;
//! Предикат для std::transform.static launch_external_t
launch_external_getter(
const tag_launch_external_t & tag )
{
return tag.get();
}
public :
tag_otherwise_t( cls_2::tag_t & owner )
:
base_type_t( owner, "otherwise", false, true )
, m_pixmap( self_tag(), "pixmap", false )
, m_bkcolor( self_tag(), "bkcolor", false )
, m_sound( self_tag(), "sound", false )
, m_log_event( self_tag(), "log_event", false )
, m_launch_external( self_tag(), "launch_external", false )
{
fill_color_constraint( m_bkcolor_constraint );
m_bkcolor.set_constraint( &m_bkcolor_constraint );
}
virtual ~tag_otherwise_t()
{}
//! Получить значения.void
get( actions_t & to ) const
{
m_pixmap.query_opt_value( to.m_pixmap );
m_bkcolor.query_opt_value( to.m_bkcolor );
m_sound.query_opt_value( to.m_sound );
if( m_log_event.is_defined() )
to.m_log_event = m_log_event.get();
if( m_launch_external.is_defined() )
std::transform( m_launch_external.begin(),
m_launch_external.end(),
std::back_inserter(
to.m_launch_external ),
launch_external_getter );
}
};
//
// tag_on_register_t
//
/*!
Класс для
*/class tag_on_register_t
: public cls_2::tag_no_value_t
{
//! Псевдоним для базового типа.typedef cls_2::tag_no_value_t base_type_t;
private :
//! Звуковой файл.
cls_2::tag_scalar_t< std::string > m_sound;
//! Событие для log_writter.
tag_log_event_t m_log_event;
//! Список внешних приложений для запуска.
cls_2::tag_vector_of_tags_t< tag_launch_external_t >
m_launch_external;
//! Предикат для std::transform.static launch_external_t
launch_external_getter(
const tag_launch_external_t & tag )
{
return tag.get();
}
public :
tag_on_register_t( cls_2::tag_t & owner )
:
base_type_t( owner, "on_register", false, true )
, m_sound( self_tag(), "sound", false )
, m_log_event( self_tag(), "log_event", false )
, m_launch_external( self_tag(), "launch_external", false )
{}
virtual ~tag_on_register_t()
{}
//! Получить значения.void
get( actions_t & to ) const
{
m_sound.query_opt_value( to.m_sound );
if( m_log_event.is_defined() )
to.m_log_event = m_log_event.get();
if( m_launch_external.is_defined() )
std::transform( m_launch_external.begin(),
m_launch_external.end(),
std::back_inserter(
to.m_launch_external ),
launch_external_getter );
}
};
//
// tag_on_deregister_t
//
/*!
Класс для
*/class tag_on_deregister_t
: public cls_2::tag_no_value_t
{
//! Псевдоним для базового типа.typedef cls_2::tag_no_value_t base_type_t;
private :
//! Звуковой файл.
cls_2::tag_scalar_t< std::string > m_sound;
//! Событие для log_writter.
tag_log_event_t m_log_event;
//! Список внешних приложений для запуска.
cls_2::tag_vector_of_tags_t< tag_launch_external_t >
m_launch_external;
//! Предикат для std::transform.static launch_external_t
launch_external_getter(
const tag_launch_external_t & tag )
{
return tag.get();
}
public :
tag_on_deregister_t( cls_2::tag_t & owner )
:
base_type_t( owner, "on_deregister", false, true )
, m_sound( self_tag(), "sound", false )
, m_log_event( self_tag(), "log_event", false )
, m_launch_external( self_tag(), "launch_external", false )
{}
virtual ~tag_on_deregister_t()
{}
//! Получить значения.void
get( actions_t & to ) const
{
m_sound.query_opt_value( to.m_sound );
if( m_log_event.is_defined() )
to.m_log_event = m_log_event.get();
if( m_launch_external.is_defined() )
std::transform( m_launch_external.begin(),
m_launch_external.end(),
std::back_inserter(
to.m_launch_external ),
launch_external_getter );
}
};
//
// tag_data_class_t
//
/*!
Класс для разбора описания типа источника данных.
*/template< class T >
class tag_data_class_t
: public cls_2::tag_scalar_t< std::string >
{
//! Псевдоним для базового типа.typedef cls_2::tag_scalar_t< std::string > base_type_t;
private :
//! Приоритет.
cls_2::tag_scalar_t< unsigned int > m_priority;
//! Ограничения на приоритет.
cls_2::scalar_constraint::min_max_t<
unsigned int >
m_priority_range;
//! Величина шрифта в пунктах.
cls_2::tag_scalar_t< int > m_font_size;
//! Тип списка тегов-условий.typedef cls_2::tag_vector_of_tags_t< tag_if_t< T > >
tag_conditions_t;
//! Список условий.
tag_conditions_t m_conditions;
//! Действия по умолчанию.
tag_otherwise_t m_otherwise;
//! Действие, выполняемое при регистрации источника данных
tag_on_register_t m_on_register;
//! Действие, выполняемое при дерегистрации источника данных
tag_on_deregister_t m_on_deregister;
public :
//! Основной конструктор.
tag_data_class_t(
const char * name,
bool is_mandatory )
:
base_type_t( name, is_mandatory )
, m_priority( self_tag(), "priority", true )
, m_priority_range( 0, 9 )
, m_font_size( self_tag(), "font_size", false )
, m_conditions( self_tag(), "if", false )
, m_otherwise( self_tag() )
, m_on_register( self_tag() )
, m_on_deregister( self_tag() )
{
m_priority.set_constraint( &m_priority_range );
}
virtual ~tag_data_class_t()
{}
//! Получить значения.
data_class_t< T >
get() const
{
data_class_t< T > to;
to.m_priority = m_priority.query_value();
if( m_otherwise.is_defined() )
m_otherwise.get( to.m_otherwise );
if( m_on_register.is_defined() )
m_on_register.get( to.m_on_register );
if( m_on_deregister.is_defined() )
m_on_deregister.get( to.m_on_deregister );
m_font_size.query_opt_value( to.m_font_size );
for( unsigned int i = 0, i_max = m_conditions.size();
i != i_max; ++i )
{
to.m_conditions.push_back(
m_conditions.at( i ).get() );
}
return to;
}
};
Собственно код был написан наспех и с тех пор рефакторингу из-за отсутствия времени не подвергался, поэтому классы tag_on_register_t и tag_on_deregister_t остались реализованными через copy&paste (изначально планировалось, что у них будет разных набор дочерних тегов).
Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>А так всегда -- на словах все мудрецы и монстры. А как до реальных решений доходит, то "твои проблемы", "горы кода".
Умение четко и кратко сформулировать вопрос — это действительно твои проблемы. Многие вопросы остающиеся без ответа отсаются без оного только из-за того, что они слишком запвтаны и противоричивы.
E>Я помниться когда-то спросил, почему Янус на C++ не был написан. Так я стал сразу одним из тех самых умных, которые никогда ничего не делают.
Ты стал одним из тех которые никогда не сделают свою версию Януса. А про то что ты ничего не делаешь никто не говорил.
E> А здесь реальная проблема, которая на C++ решилась без труда и могла бы быть решена еще проще.
Опиши эту проблему. Только проблему, а не решение. И по возможности кратко и понятно.
E> Но стоило всего лишь поинтересоваться, как ее решить средствами generic-ов, как C#-евангелисты отмазки начали приводить.
Тебе замечательно ответил С++-ник. Попробуй воспринять его слова.
E> Здорово (еще бы, это не C# c Python-ом в разработке игр применять). Только проблема в том, что я и так привел минимальный реальный код. В дейсвительности там еще больше навороты на более высоких уровнях есть. И на C++ это все работает и является сопровождаемым.
Я так понимаю, ты не первый год программируешь. Раз так то должен понимать, что ценить нужно не навороты, а стройность и простоту кода. А навороты и дерзкие хаки пусть наворачивают молодые кул-хацкеры.
Лично я когда пишу код на Шарпе не испытываю потребности в замазывании дяр в виде трехэтажных конструкциях. Рефакторю часто. Паттерны разные применяю часто. А вот хаки как-то не нужны.
VD>>Скорее всего твои проблемы связанны с тем, что ты хочешь решать задачи на C# так же как если бы ты решал их на С++.
E>Я не хочу решать задачи на C#. Мне просто интересно, как это могло бы быть.
Проблема в том, что а) я лично не понял что тебе нужно, б) твои проблемы скорее всего являются следствием тараканов заведшихся от С++-мышления. Я открою тебе небольшой сикрет. Я программировал на С++ значительно дольше чем на Шарпе и в первое время, после перехода на Шарпм, тоже пытался писать как на С++. Потом понял неразумность этого и переучился на новый стиль.
E>Ok. Статью посмотрю. Подумаю. E>Сериализаций для C++ как собак нерезанных.
Ага. И все как одна неудобны В дотнете для того чтобы объект сериализовался достаточно добавить один атрибут. Разные хитрые случаи тоже разруливаются на атрибутах. В общем, другой мир.
E> Сам персонально одной такой занимаюсь -- успешно применяется в production code уже около 2-х лет и нет проблем.
Дошол до первого примера и дальше смотреть не стал. Как всегда куча сложностей на ровном месте. Почитай про BinaryFormatter и про XmlSerializer (в приведенной выше статье). Думаю разницу ты ощутишь сразу.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
E>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
Это в подтверждение закона Гринспуна о том, что в каждой программе на С++ есть, пусть слабенький, но интерпритатор лиспа?
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, eao197, Вы писали: E>>Алаверды привожу код на C++ для парсинга конфигов следующего вида: E>>
E>>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
ANS>Это в подтверждение закона Гринспуна о том, что в каждой программе на С++ есть, пусть слабенький, но интерпритатор лиспа?
Нет, на самом деле синтаксис был навеян языком Curl, а уж откуда ноги растут у Curl-а мне было не важно
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, eao197, Вы писали:
E>>А так всегда -- на словах все мудрецы и монстры. А как до реальных решений доходит, то "твои проблемы", "горы кода".
VD>Умение четко и кратко сформулировать вопрос — это действительно твои проблемы. Многие вопросы остающиеся без ответа отсаются без оного только из-за того, что они слишком запвтаны и противоричивы.
Да, такое может быть.
E>> А здесь реальная проблема, которая на C++ решилась без труда и могла бы быть решена еще проще.
VD>Опиши эту проблему. Только проблему, а не решение. И по возможности кратко и понятно.
А зачем? Ответ я от Павла Кузнецова получил. Воспринял и поставил соответствующую оценку.
E>> Здорово (еще бы, это не C# c Python-ом в разработке игр применять). Только проблема в том, что я и так привел минимальный реальный код. В дейсвительности там еще больше навороты на более высоких уровнях есть. И на C++ это все работает и является сопровождаемым.
VD>Я так понимаю, ты не первый год программируешь. Раз так то должен понимать, что ценить нужно не навороты, а стройность и простоту кода. А навороты и дерзкие хаки пусть наворачивают молодые кул-хацкеры.
Стройность и простота -- очень относительные понятия. И во многом зависят от квалификации разработчика. Для продвинутого C++ программиста использование boost::bind гораздо проще и понятнее, чем для начинающего (либо даже для C++ программиста с многолетним опытом, но не работавшем с шаблонами). Поэтому они могут дать совершенно разные оценки одному и тому же коду.
VD>Лично я когда пишу код на Шарпе не испытываю потребности в замазывании дяр в виде трехэтажных конструкциях. Рефакторю часто. Паттерны разные применяю часто. А вот хаки как-то не нужны.
Еще раз повторю -- в том конкретном случае нужно было сделать рефакторинг в базисе, на котором строилось много другого кода и который использовали другие проекты, к которым я даже отношения не имел. Если бы я нарушил совместимость на уровне исходного кода, то во всех этих проектах потребовался бы рефакторинг. И его стоимость бы оказалась гораздо выше полезности той фичи, которую я хотел добавить.
VD>>>Скорее всего твои проблемы связанны с тем, что ты хочешь решать задачи на C# так же как если бы ты решал их на С++.
E>>Я не хочу решать задачи на C#. Мне просто интересно, как это могло бы быть.
VD>Проблема в том, что б) твои проблемы скорее всего являются следствием тараканов заведшихся от С++-мышления. Я открою тебе небольшой сикрет.
Да, это я уже понял. Точно так же, как то, что C++ пытаются оценивать, используя тараканов из C#.
E>> Сам персонально одной такой занимаюсь -- успешно применяется в production code уже около 2-х лет и нет проблем.
VD>Дошол до первого примера и дальше смотреть не стал. Как всегда куча сложностей на ровном месте.
)? Ты, кстати, прочитал, для демонстрации чего был создан этот пример?
VD> Почитай про BinaryFormatter и про XmlSerializer (в приведенной выше статье). Думаю разницу ты ощутишь сразу.
Что-то я там с ходу не увидел, как с помощью BinaryFormatter можно десериализовать объекты, про которые принимающая сторона даже понятия не имеет? Или BinaryFormatter содержит в себе больше возможностей чем ASN1?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, VladD2, Вы писали:
VD>>Если ты действительно хочешь что-то сравнить, то порпробуй ответить на вопрос как на С++ сделать вот это: http://rsdn.ru/article/dotnet/dnetappcfg.xml
или как сделать сериализацию на С++ такой же простой как в дотнете.
E>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
Прелесть XML не в том, что требуется меньше закорючек для описания структуры, и не в том, что его проще редактировать вручную, а в том, что он — СТАНДАРТ. С самопальными примочками типа Вашей можете разобраться только Вы. Для неё не сущесвует таких полезных и удобных технологий, как XML Schema (проверка), XSLT (преобразование), XPATH (запросы). Пользователи не смогут воспользоваться внешними высокоуровневыми редакторами этих файлов (а могли бы, если бы была XML схема).
...
Эх, велосипедный спорт пользуется огромной популярностью...
Здравствуйте, ihatelogins, Вы писали:
I>Здравствуйте, eao197, Вы писали:
E>>Здравствуйте, VladD2, Вы писали:
VD>>>Если ты действительно хочешь что-то сравнить, то порпробуй ответить на вопрос как на С++ сделать вот это: http://rsdn.ru/article/dotnet/dnetappcfg.xml
или как сделать сериализацию на С++ такой же простой как в дотнете.
E>>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
I>Прелесть XML не в том, что требуется меньше закорючек для описания структуры, и не в том, что его проще редактировать вручную, а в том, что он — СТАНДАРТ.
Стандарт чего?
Имхо, применение XML для конфигов объемом в 100-200 строк -- это из пушки по воробъям.
I> С самопальными примочками типа Вашей можете разобраться только Вы. Для неё не сущесвует таких полезных и удобных технологий, как XML Schema (проверка), XSLT (преобразование), XPATH (запросы). Пользователи не смогут воспользоваться внешними высокоуровневыми редакторами этих файлов (а могли бы, если бы была XML схема).
Справедливо. Но зачем для конфигурационных файлов XML Schema, XSLT, XPATH и пр. понять не могу.
I>Эх, велосипедный спорт пользуется огромной популярностью...
Да, и я большой его сторонник
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Посмотрел, увидел теже самые тоны кода. Подумал, не понял что должен был ответить.
Видимо не туда смотрел.
Если тебе влом вчитываться в суть статьи могу продемонстрировать упрощенный пример. Вот хэлпер-класс для упрощения сериализации в строку (в хмл-формате):
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
static class MySerializer
{
public static string Serialize<T>(T obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(sb, settings))
serializer.Serialize(writer, obj);
return sb.ToString();
}
public static T Deserialize<T>(string data)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (XmlReader reader = XmlTextReader.Create(new StringReader(data)))
return (T)serializer.Deserialize(reader);
}
}
Пишется один раз.
А вот как выглядит пример сериализации содержимого класса с его использованим:
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
public class Test
{
public int Age; // Просто поле
// Далее все на свойствахprivate string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
// Сериализуем коллекцию строк. Тоже все почит в автомате.
List<string> _addresses = new List<string>();
// Атрибут XmlArrayItem позволяет задать имя для элементов
// содержащих конкретные адреса. Если его не указать, то они
// будут иметь имя "<string>".
[XmlArrayItem("Address")]
public List<string> Addresses
{
get { return _addresses; }
}
}
class Program
{
static void Main(string[] args)
{
Test test = new Test();
test.Age = 31;
test.FirstName = "Чистяков";
test.LastName = "Влад";
test.Addresses.Add("Первый адрес");
test.Addresses.Add("Второй адрес");
// Сохраняем состояние в ХМЛ.string data = MySerializer.Serialize(test);
Console.WriteLine("Выводим сериализованные данные:");
Console.WriteLine(data);
test = null;
Console.WriteLine();
Console.WriteLine("Выводим содержимое объекта состояние "
+ "которого только что считано из строки:");
// Загружаем состояние...
test = MySerializer.Deserialize<Test>(data);
Console.WriteLine("FirstName: " + test.FirstName);
Console.WriteLine("Address 1: " + test.Addresses[0]);
}
}
Как видишь практически никаких лишних телодвижений. Код получается чистым и красивым.
E>Ну сделали вы для C# удобное решение с использованием встроенной в платформу поддержки XML сериализации и атрибутами (или как они в .Net-е называются). И что, это должно было продемонстрировать преимущества C# над C++? Ok. Если ты в этом уверен, то пусть в данной конкреной области будет так.
Не. Это демонстрция возможностей компонентного подхода. На С++ без внешнего хранилища метаинформации и без отдельного генератора код подобное сделать не удастся. Любые выкрутасы на шаблонах приведут к куче лишних движений при программировании и все равно окажутся мнее гибкими и более медленными нежели это.
Причем не нужно пытаться сомтреть на этот пример как не некую магию предоставляемую фрэймворком. XmlSerializer — это обыкновенный класс написанный на C#. Просто он задействует самые мощьные фичи дотнета вроде рефлекшона, компиляции в рантайме и динамической загрузки сборок.
E>Алаверды привожу код на C++ для парсинга конфигов следующего вида:
...
Хотел было оставить всю эту гору кода чтобы в конце поставить смайли, но уж очень огромный оверквотинг вышел бы. К тому же это все не смешно. Это грустно.
Фиг с бы с тем, что формат конфига стршен сам по себе. Но такие горы кода для столь простых задачь. Зачем?
E>Собственно код был написан наспех и с тех пор рефакторингу из-за отсутствия времени не подвергался, поэтому классы tag_on_register_t и tag_on_deregister_t остались реализованными через copy&paste (изначально планировалось, что у них будет разных набор дочерних тегов).
Прочитать эту гору кода я лично не в состоянии. (время жалко) Так что заметить подобные мелочи просто не смог. Но ты привел замечательный пример того сколько кода нужно надалбливать на С++ чтобы решить примитивные задачи.
Как я понимаю твой код не умеет впихивать информацию в объекты и читать ее из них. Попробуй ради хохмы добавить такую возможность.
E>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
Гы-гы. Это типичный пример заката слонца вручную. Если уж разрабатывался свой формат файла, да еще с зачатками языка программировани, то нужно было просто описать его грамтику в BNF/EBNF нотации и скормить любому генератору парсеров. Уверяю тебя, что даже н С++ объем кода сократился бы до пары страниц. Что до твоего формата, то извини, но это тоже велосипед. Этот формат придется изучать. А что до простоты правки... дык ХМЛ то можно править редакторами поддреживающими схемы. При этом убдет и комплит и подсветка. Твой же формат прдется править как плоский текст. Так что что удобнее еще не известно.
Если же ты попыташься внимательно прочесть статью на которую я давал ссылку, то ты увидишь, что благодоря развитой компонентной модели в дотнете можно относительно малой кровью реализовать и качественное ГУИ для редактирования данных хранящихся непосредственно в объекте. Причем код будет универсальный и ему можно будет подсовывать любой объект размеченный специальными атрибутами. В стаье этого нет, но эта схема, в Янусе, на сегодня ко всему прочему поддерживает многоязычную поддржку.
Все это конечно можно написать на С++, но это будет не один человекогод. И так почти в каждой области. Именно по этому мы (разработчики Януса) смело заявляем, что повторить Янус на С++ на объщественных началах практически невозможно.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Да.
> Это демонстрция возможностей компонентного подхода. На С++ без > внешнего хранилища метаинформации и без отдельного генератора код > подобное сделать не удастся. Любые выкрутасы на шаблонах приведут к > куче лишних движений при программировании и все равно окажутся мнее > гибкими и более медленными нежели это.
Был бы в С++ нормальный compile-time reflection — все стало бы еще
намного проще.
> Все это конечно можно написать на С++, но это будет не один > человекогод. И так почти в каждой области. Именно по этому мы > (разработчики Януса) смело заявляем, что повторить Янус на С++ на > объщественных началах практически невозможно.
Берем Thunderbird и пишем к ней расширение для RSDN. На С++
<...код поскипан...> VD>Как видишь практически никаких лишних телодвижений. Код получается чистым и красивым.
Влад, ты сам, вероятно, мало читаешь то, что пишут опоненты, поэтому и других в этих грехах обвиняешь?
Код получается нормальным. Почти как в boost::serialization
Если серьезно, то я признаю, что в C# удобно делать сериализацию в XML. Так ведь для языка, который появился в расцвет XML-я это и не удивительно, не так ли?
E>>Ну сделали вы для C# удобное решение с использованием встроенной в платформу поддержки XML сериализации и атрибутами (или как они в .Net-е называются). И что, это должно было продемонстрировать преимущества C# над C++? Ok. Если ты в этом уверен, то пусть в данной конкреной области будет так.
VD>Не. Это демонстрция возможностей компонентного подхода. На С++ без внешнего хранилища метаинформации и без отдельного генератора код подобное сделать не удастся. Любые выкрутасы на шаблонах приведут к куче лишних движений при программировании и все равно окажутся мнее гибкими и более медленными нежели это.
Ой-ли? Не убедительно. Лично я останусь при своем мнении.
E>>Алаверды привожу код на C++ для парсинга конфигов следующего вида: VD>...
VD>Хотел было оставить всю эту гору кода чтобы в конце поставить смайли, но уж очень огромный оверквотинг вышел бы. К тому же это все не смешно. Это грустно.
VD>Фиг с бы с тем, что формат конфига стршен сам по себе.
Это дело вкуса. По мне, так гораздо страшнее было бы работать с конфигом вида:
# Our web share
resource drbd0 {
net {
sync-group=0
}
on node1 {
device=/dev/nb0
disk=/dev/sda1
}
on node2 {
device=/dev/nb0
disk=/dev/sda1
}
}
# Our MySQL share
resource drbd1 {
net {
sync-group=1
}
on node1 {
device=/dev/nb1
disk=/dev/sda2
}
on node2 {
device=/dev/nb1
disk=/dev/sda2
}
}
Неужели бы он выиграл бы от XML-формата?
VD>Но такие горы кода для столь простых задачь. Зачем?
Ну я в свое время насмотрелся (на Java и C++), как хранят конфиги в XML а затем извлекают из них значения. Если используется DOM-модель, то после нескольких строчек обращения к парсингу шла масса строк с поиском и извлечением значений из DOM-элементов. А если использовалась SAX-модель, то код все равно получался таким же, как у меня, только нужно было еще корректно из строк в int-ы преобразовывать.
VD>Как я понимаю твой код не умеет впихивать информацию в объекты и читать ее из них. Попробуй ради хохмы добавить такую возможность.
Вот именно -- ради хохмы. А в реальности мне такая фишка пока не потребовалась.
E>>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
VD>Гы-гы. Это типичный пример заката слонца вручную. Если уж разрабатывался свой формат файла, да еще с зачатками языка программировани, то нужно было просто описать его грамтику в BNF/EBNF нотации и скормить любому генератору парсеров.
Там нет зачатков языка программирования. Просто похожие конструкции.
Кроме того, у граматик и парсеров есть большие проблемы с раширяемостью. Вот потребуется в тег {pixmap} еще один подтег добавить, и придется граматику править. И еще не понятно, насколько проще это окажется, особенно если граматика получится сильно контекстно-чувствительная.
VD>Если же ты попыташься внимательно прочесть статью на которую я давал ссылку, то ты увидишь, что благодоря развитой компонентной модели в дотнете можно относительно малой кровью реализовать и качественное ГУИ для редактирования данных хранящихся непосредственно в объекте. Причем код будет универсальный и ему можно будет подсовывать любой объект размеченный специальными атрибутами. В стаье этого нет, но эта схема, в Янусе, на сегодня ко всему прочему поддерживает многоязычную поддржку.
Влад, я прочел статью.
Но оценить всю видимую тобой прелесть я не могу. Вероятно в силу того, что занимаюсь другими вещами.
VD>Именно по этому мы (разработчики Януса) смело заявляем, что повторить Янус на С++ на объщественных началах практически невозможно.
Имхо, тебе пора перестать использовать в качестве доказательства крутости C# тот факт, что на C++ нет аналога Януса. На C# нет аналога GNOME или KDE, почему бы не сказать, что на C# эти проекты нереализуемы?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Шутку понял. Смешно.
>> Это демонстрция возможностей компонентного подхода. На С++ без >> внешнего хранилища метаинформации и без отдельного генератора код >> подобное сделать не удастся. Любые выкрутасы на шаблонах приведут к >> куче лишних движений при программировании и все равно окажутся мнее >> гибкими и более медленными нежели это.
C>http://boost.org/libs/serialization/doc/index.html , в частности C>http://boost.org/libs/serialization/doc/tutorial.html#simplecase
Да, хорошая демонстрация очередного заката солнца вручную. Ради хохмы приведу аналог вот этого:
class gps_position
{
private:
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<. Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & degrees;
ar & minutes;
ar & seconds;
}
int degrees;
int minutes;
float seconds;
public:
gps_position(){};
gps_position(int d, int m, float s) :
degrees(d), minutes(m), seconds(s)
{}
};
на Шарпе:
[Serializable]
class gps_position
{
private int degrees;
private int minutes;
private float seconds;
};
C>Был бы в С++ нормальный compile-time reflection — все стало бы еще C>намного проще.
Был бы у бабушки хрен...
>> Все это конечно можно написать на С++, но это будет не один >> человекогод. И так почти в каждой области. Именно по этому мы >> (разработчики Януса) смело заявляем, что повторить Янус на С++ на >> объщественных началах практически невозможно.
C>Берем Thunderbird и пишем к ней расширение для RSDN. На С++
Ага... языком.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, eao197, Вы писали:
E>>Справедливо. Но зачем для конфигурационных файлов XML Schema, XSLT, XPATH и пр. понять не могу.
AVK>Ну что ж — тогда могу просоветовать попробовать любой современный IDE, понимающий XML-Schema.
А уж IDE-то здесь к чему?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>>>Справедливо. Но зачем для конфигурационных файлов XML Schema, XSLT, XPATH и пр. понять не могу.
AVK>>Ну что ж — тогда могу просоветовать попробовать любой современный IDE, понимающий XML-Schema.
E>А уж IDE-то здесь к чему?
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, eao197, Вы писали:
E>>>>Справедливо. Но зачем для конфигурационных файлов XML Schema, XSLT, XPATH и пр. понять не могу.
AVK>>>Ну что ж — тогда могу просоветовать попробовать любой современный IDE, понимающий XML-Schema.
E>>А уж IDE-то здесь к чему?
AVK>Попробуй — узнаешь
Хотя бы для какого языка программирования эта IDE должна быть?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, ihatelogins, Вы писали:
I>>Здравствуйте, eao197, Вы писали:
E>>>Здравствуйте, VladD2, Вы писали:
VD>>>>Если ты действительно хочешь что-то сравнить, то порпробуй ответить на вопрос как на С++ сделать вот это: http://rsdn.ru/article/dotnet/dnetappcfg.xml
или как сделать сериализацию на С++ такой же простой как в дотнете.
E>>>Имхо, на C++ без существенных издержек и накладных расходов был реализован разбор сложных конфигурационных файлов. Причем не XML формата, а более удобного для редактирования вручную.
I>>Прелесть XML не в том, что требуется меньше закорючек для описания структуры, и не в том, что его проще редактировать вручную, а в том, что он — СТАНДАРТ.
E>Стандарт чего?
Стандарт описания структурированной информации.
E>Имхо, применение XML для конфигов объемом в 100-200 строк -- это из пушки по воробъям.
Использование XML оправдано даже для config-файлов в 1 строку. Размер файла значения не имеет.
I>> С самопальными примочками типа Вашей можете разобраться только Вы. Для неё не сущесвует таких полезных и удобных технологий, как XML Schema (проверка), XSLT (преобразование), XPATH (запросы). Пользователи не смогут воспользоваться внешними высокоуровневыми редакторами этих файлов (а могли бы, если бы была XML схема).
E>Справедливо. Но зачем для конфигурационных файлов XML Schema, XSLT, XPATH и пр. понять не могу.
XML Schema — для проверки корректности структуры.
XSLT в HTML может быть удобен для визуального отображения config-файла.
XPath можеь быть использован для быстрого получения конкретных настроек в config-файле в сторонних приложениях.
Как видите, всё логично, и, САМОЕ ГЛАВНОЕ, стандартизованно. Проще разрабатывать СЕЙЧАС, легче (дешевле, быстрее) поддерживать в будущем.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, eao197, Вы писали:
E>> E>>Хотя бы для какого языка программирования эта IDE должна быть?
AVK>Для любого. Подойдет VS2003-2005, IDEA.
С такими выражениями стоило бы быть поосторожнее. VS2003 -- это C++, C#, VB (или что-то еще)? IDEA -- это Java.
Но под понятие "любой" подойдут так же языки Perl, Python, Ruby, Smalltalk, Oberon, Ada, Modula-2, Eiffel, Prolog, Lisp (все, что сразу удалось вспомнить) и еще куча языков.
Так что-же я должен увидеть?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.