【问题标题】:A method of combining serialization with grammar parsing?一种将序列化与语法解析相结合的方法?
【发布时间】:2011-02-03 01:58:44
【问题描述】:

我遇到了一个难题。我的 C# 应用程序使用自定义文件格式,需要在文本编辑器中进行人工编辑,但也可以通过我的应用程序中的 GUI 进行编辑。该文件将表示一个顶级对象(称为 TopObject),其中包含几个较小的对象,这些较小的对象又包含其他对象,依此类推。这些对象中包含的所有数据都在文件中提供。

我不知道如何解决加载/保存这些文件的问题。 C# 序列化对我不起作用,因为它破坏了人类可编辑性(二进制序列化)或在序列化基类集合时存在“问题”(XML 和 DataContract 序列化,在序列化基类时添加文本以消除派生类的歧义,这使文件更易被人工编辑);如果不是因为需要手动编辑文件,那将是票。我一直在研究 GOLD 和 GPLEX/GPPG 等解析器生成器来解析文件并将其转换为它们所代表的对象,它看起来很有希望,但这仅涵盖加载文件的一个方向,并不能确保它们被保存在写出来时格式正确。

最好的方法是指定一种同时处理两者的语法:
1)读取具有指定结构的文件并将其转换为TopObject及其包含的所有对象,以及
2) 给定一个 TopObject,将其状态写入具有相同结构的文件。
几乎是一个强制导入结构以及强制输出结构的单一语法。

有没有这样的工具或框架可以帮助我?这是可行的,还是我想得太多了,有更简单的方法?

【问题讨论】:

    标签: c# parsing serialization


    【解决方案1】:

    我仍然会使用 XML,但只需编写您自己的序列化程序。您可以使用 .Net 中的 XML 读取器/写入器类来创建简单的 XML 格式:

    <TopObject>
        <SubObject>
            <SubObject>
                etc.
            </SubObject>  
            <SubObject>
                etc.
            </SubObject>
        </SubObject>
        <SubObject></SubObject>
    </TopObject>
    

    我不知道你是否认为这足够人类可读,但最好是 .Net 序列化程序创建的东西。递归地读/写很容易。

    示例:

    这是一个您可以适应的简单示例。假设我有这个类:

    public class Node {
        public Node(String _SomeProperty) {
            this.SomeProperty = _SomeProperty;
        }
    
        public String SomeProperty;
    
        public List<Node> Children = new List<Node>();
    }
    

    每个Node 都有一个属性,称为SomeProperty。它也可以有孩子; Children 属性中的更多 Nodes

    这是来自控制台应用程序的main,它从此类创建一些数据以进行序列化:

    static void Main(string[] args) {
        // Make some data for testing
        Node baseObject = new Node("This is the base class");
    
        List<Node> Children = new List<Node>(){
            new Node("This is a child"),
            new Node("This is another child")
        };
    
        baseObject.Children = Children;
    
        Node aSubChild = new Node("This is a child of a child");
        baseObject.Children[0].Children = new List<Node>() { aSubChild };
    
        // Serialize
    
        XmlWriter writer = XmlWriter.Create("test.xml");
    
        writer.WriteStartDocument();
    
    
        RecursivelySerialize(ref writer, baseObject);
        writer.Flush();
    }
    

    它调用了一个名为 RecursivelySerialize 的方法,该方法完成了实际工作:

    private static void RecursivelySerialize(ref XmlWriter writer, Node sc) {
        writer.WriteStartElement("Node");
    
        writer.WriteElementString("SomeProperty", sc.SomeProperty);
    
        if (sc.Children.Count > 0) {
            writer.WriteStartElement("Nodes");
    
            foreach (Node scChild in sc.Children)
                RecursivelySerialize(ref writer, scChild);
    
            writer.WriteEndElement();
        }
    
        writer.WriteEndElement();
    }
    

    这种方法并不复杂。为了改进它,您可以使用反射来动态序列化任何类型的类。这是我在运行上述代码时得到的输出(格式很好):

    <?xml version="1.0" encoding="utf-8"?>
    <Node>
        <SomeProperty>This is the base class</SomeProperty>
        <Nodes>
            <Node>
                <SomeProperty>This is a child</SomeProperty>
                    <Nodes>
                        <Node>
                            <SomeProperty>This is a child of a child</SomeProperty>
                        </Node>
                    </Nodes>
            </Node>
            <Node>
                <SomeProperty>This is another child</SomeProperty>
            </Node>
        </Nodes>
    </Node>
    

    【讨论】:

    • @SimpleCoder,你能举一个自定义序列化器的简单例子吗?
    【解决方案2】:

    就个人而言,我不会过多地关注使文件可人工编辑,至少非技术人员不可编辑。如果一个应用程序需要使用文件,那么它就需要准确性,无论您建立什么样的语法,人类仍然会出错。

    XML/JSON/INI 对于一些技术人员来说仍然很难不搞砸(令人惊讶),但至少它们对一些技术人员来说是熟悉的。我认为这些是比滚动自己的语法更好的选择。更好的是,如果您想让编辑文件更加用户友好,您可以考虑放弃“人工可编辑”要求并使其只能由应用程序编辑。

    【讨论】:

      猜你喜欢
      • 2015-01-22
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 2011-09-25
      相关资源
      最近更新 更多