Лучший отвечающий
Виртуальные статически функции C#

Вопрос
-
Здравствуйте. Для того, чтобы объяснить что я хочу приведу краткий пример:
У меня скажем есть дерево, каждый элемент которого наследуется от Node, добавляет свой функционал и тп. Мне нужно добавить экспорт и импорт все этого в xml. Но я не хочу смешивать xml представление и данные, поэтому хочу реализовать xml функции в виде расширения. Но хотелось бы чтобы они работали также как виртуальные, то есть для каждого объекта вызывается функция исходя из его реального типа, в моем же случае всегда будет вызываться функции связанная с Node, а соответствующие функции связанные с наследниками Node я даже определить не смогу, так как сигнатуры будут совпадать! Как добиться функционала, который я хочу? Как я понимаю, нужно копать в рефлексию, но куда именно и как лучше это все сделать?
Заранее спасибо!
- Перемещено YatajgaEditor 17 августа 2013 г. 10:44
16 августа 2013 г. 12:23
Ответы
-
Коллега, вариантов 4.
1. Вы делаете методы для преобразования ноды в строку содержащую XML элемент (этот процесс и называется сериализацией), в каждой ноде (классическая виртуализация), но в этом случае, у вас будет проблема с десериализацией, т.к. считав ноду вы не знаете какой метод вызывать.
2. Вы делаете как я показал вам в сериализации и по аналогичной схеме, только анализируя не тип ноды, а имя считанного элемента создаете ноду.
3. Применение табличного метода, что будет являться улучшенным вариантом от предыдущего. Для сериализации вы используете массив вида:
List<Type, Function<Node, string>> serialisers
В котором вы храните пары тип - метод для сериализации.
Получив ноду, ищите ее в тип в этом массиве, вызываете соответсвующий метод на ноде в результате получаете строку для вставки в XML.
Для десериализации вам понадобиться массив вида:
List<string, Function<string, Node>> deserialisers
В котором будут храниться пары имя ноды - метод преобразования строки содержащией ноду в ноду заданного типа.
На мой взгляд самый удачный вариант, пишите 2 * N методов, при добавлении N+1 типа ноды, вам нужно написать два метода сериализации/десереализации и добавить их в соответствующие массивы.
4. Reflection. Все то же самое что и во втором случае, но у вас методы имеют имена Serialise<имя типа> и Deserialise<имя типа>. В этом случае получив имя типа ноды или имя элемента вы через Reflection находите соответствующий метод.
По прежнему пишите 2* N методов, при добавлении N+1 типа ноды, вам нужно написать два метода сериализации/десереализации, массивы поддерживать не надо, т.к. получаете методы через Reflection. Но, как всегда но, за именами методов нужно следить очень внимательно и если ошибетесь, то долго будите ловить ошибку в процессе работы, т.к. все что идет через Rfelection на этапе компиляции не анализируется.
- Помечено в качестве ответа Ruzik 16 августа 2013 г. 13:40
16 августа 2013 г. 13:20Отвечающий
Все ответы
-
Добрый день.
1. Виртуальных статических функций не существует.
2. Виртуальные функции это по большому счету замена условий. Вот, можете почитать здесь.
3. Зачем Reflection? Сделайте в своем методе что то типа такого (node это нода для сериализации):
if (node is Node) { // Логика сохранения базовых нод } else if (node is NodeChild1) { // Логика сохранения нод от класса NodeChild1 } else if (node is NodeChild2) { // Логика сохранения нод от класса NodeChild2 }
16 августа 2013 г. 12:48Отвечающий -
Виртуальных статических функций не существует.
___________
Оно и понятно =) Мне нужно что-то дающее соответствующий эффект.Зачем Reflection? Сделайте в своем методе что то типа такого (node это нода для сериализации):
________________
Такой способ вряд ли подойдет, так как при каждом новом наследнику будет нужно дописывать эту реализацию. К тому же я не смогу удобно работать в этом случае:class NewNode : Node { public virtual void FromXml(XElement e) { base.FromXml(e); //Дальнейший разбор xml } }
Да и к тому же если бы я мог воспользоваться серриализацией, то проблема была бы решена, но я не могу из-за накладываемых ею ограничений.
16 августа 2013 г. 12:55 -
Коллега, вариантов 4.
1. Вы делаете методы для преобразования ноды в строку содержащую XML элемент (этот процесс и называется сериализацией), в каждой ноде (классическая виртуализация), но в этом случае, у вас будет проблема с десериализацией, т.к. считав ноду вы не знаете какой метод вызывать.
2. Вы делаете как я показал вам в сериализации и по аналогичной схеме, только анализируя не тип ноды, а имя считанного элемента создаете ноду.
3. Применение табличного метода, что будет являться улучшенным вариантом от предыдущего. Для сериализации вы используете массив вида:
List<Type, Function<Node, string>> serialisers
В котором вы храните пары тип - метод для сериализации.
Получив ноду, ищите ее в тип в этом массиве, вызываете соответсвующий метод на ноде в результате получаете строку для вставки в XML.
Для десериализации вам понадобиться массив вида:
List<string, Function<string, Node>> deserialisers
В котором будут храниться пары имя ноды - метод преобразования строки содержащией ноду в ноду заданного типа.
На мой взгляд самый удачный вариант, пишите 2 * N методов, при добавлении N+1 типа ноды, вам нужно написать два метода сериализации/десереализации и добавить их в соответствующие массивы.
4. Reflection. Все то же самое что и во втором случае, но у вас методы имеют имена Serialise<имя типа> и Deserialise<имя типа>. В этом случае получив имя типа ноды или имя элемента вы через Reflection находите соответствующий метод.
По прежнему пишите 2* N методов, при добавлении N+1 типа ноды, вам нужно написать два метода сериализации/десереализации, массивы поддерживать не надо, т.к. получаете методы через Reflection. Но, как всегда но, за именами методов нужно следить очень внимательно и если ошибетесь, то долго будите ловить ошибку в процессе работы, т.к. все что идет через Rfelection на этапе компиляции не анализируется.
- Помечено в качестве ответа Ruzik 16 августа 2013 г. 13:40
16 августа 2013 г. 13:20Отвечающий -
Воспользуюсь 3 вариантом, спасибо за помощь!16 августа 2013 г. 13:35
-
Да не за что. Обращайтесь. Если какой-то из ответов помог с вашим вопросом, не забудьте его отметить.16 августа 2013 г. 13:39Отвечающий
-
"Но хотелось бы чтобы они работали также как виртуальные, то есть для каждого объекта вызывается функция исходя из его реального типа, в моем же случае всегда будет вызываться функции связанная с Node, а соответствующие функции связанные с наследниками Node я даже определить не смогу, так как сигнатуры будут совпадать! Как добиться функционала, который я хочу? "- ещё один вариант в дополнение. Делаете интерфейс с методом сериализации и десериализациии. Реализуете его в каждом типе и всё. Плохого в том, что каждый тип будет реализовывать собственную логику в себе - нет.
Сделаем содержимое сообщества лучше, вместе!
16 августа 2013 г. 18:54Модератор -
Да в том-то и дело, что есть плохое. Мы смешиваем данные и их представление. И тогда если, скажем, будет поддерживаться экспорт/импорт в JSON/Xml/MySql, то мы будем иметь кучу кода в реализации класса, которая не должна там находиться.16 августа 2013 г. 19:02
-
Такой подход практикует Microsoft в своих библиотеках, мы в своих с другой стороны. И до сих пор я в этом ничего плохого не видел за свою практику.
Сделаем содержимое сообщества лучше, вместе!
16 августа 2013 г. 19:06Модератор -
Мы видимо друг с другом просто не поняли друг друга. Если делать именно серриализацией и добавлять условно говоря элементы в модель серриализации, то естественно нет никакой особой нужды выделять эту логику в отдельный класс, но проблема в том, что мне серриализация не подходит, так как требует наличие конструктора без аргументов, чего я не могу себе позволить в виду безопасности, и поэтому весь импорт/экспорт я буду реализовывать вручную для каждого формата.
- Изменено Ruzik 16 августа 2013 г. 19:12
16 августа 2013 г. 19:11