none
Виртуальные статически функции C# RRS feed

  • Вопрос

  • Здравствуйте. Для того, чтобы объяснить что я хочу приведу краткий пример:

    У меня скажем есть дерево, каждый элемент которого наследуется от 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