带有预共享字典的.NET二进制XML

Soo*_*nts 8 .net c# .net-4.0 datacontractserializer c#-4.0

我正在使用XmlDictionaryWriter将对象序列化为具有数据协定序列化程序的数据库.它的效果很好,尺寸和速度都比使用text/xml好2倍.

但是,我将不得不处理我的数据库中的大量记录,其中任何额外的字节直接转换为数据库大小的千兆字节.这就是为什么我喜欢通过使用XML字典来进一步缩小尺寸.

我怎么做?

我看到XmlDictionaryWriter.CreateBinaryWriter静态方法接受IXmlDictionary类型的第2个参数.MSDN说"XmlDictionary用作共享字典".

首先,我尝试使用系统提供的实现:

XmlDictionary dict = new XmlDictionary();
string[] dictEntries = new string[]
{
    "http://schemas.datacontract.org/2004/07/MyContracts",
    "http://www.w3.org/2001/XMLSchema-instance",
    "MyElementName1",
    "MyElementName2",
    "MyElementName3",
};
foreach ( string s in dictEntries )
        dict.Add( s );
Run Code Online (Sandbox Code Playgroud)

结果是.NET框架完全忽略了字典,仍然将上述字符串作为纯文本插入,而不是仅引用相应的字典条目.

然后我创建了自己的IXmlDictionary实现:

class MyDictionary : IXmlDictionary
{
    Dictionary<int, string> values = new Dictionary<int, string>();
    Dictionary<string, int> keys = new Dictionary<string, int>();

    MyDictionary()
    {
        string[] dictEntries = new string[]
        {
            "http://schemas.datacontract.org/2004/07/MyContracts",
            "http://www.w3.org/2001/XMLSchema-instance",
            "MyElementName1",
            "MyElementName2",
            "MyElementName3",
        };

        foreach ( var s in dictEntries )
            this.Add( s );
    }

    static IXmlDictionary s_instance = new MyDictionary();
    public static IXmlDictionary instance { get { return s_instance; } }

    void Add( string val )
    {
        if ( keys.ContainsKey( val ) )
            return;
        int id = values.Count + 1;
        values.Add( id, val );
        keys.Add( val, id );
    }

    bool IXmlDictionary.TryLookup( XmlDictionaryString value, out XmlDictionaryString result )
    {
        if ( value.Dictionary == this )
        {
            result = value;
            return true;
        }
        return this.TryLookup( value.Value, out result );
    }

    bool IXmlDictionary.TryLookup( int key, out XmlDictionaryString result )
    {
        string res;
        if ( !values.TryGetValue( key, out res ) )
        {
            result = null;
            return false;
        }
        result = new XmlDictionaryString( this, res, key );
        return true;
    }

    public bool /* IXmlDictionary. */ TryLookup( string value, out XmlDictionaryString result )
    {
        int key;
        if ( !keys.TryGetValue( value, out key ) )
        {
            result = null;
            return false;
        }

        result = new XmlDictionaryString( this, value, key );
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

结果是 - 我的TryLookup方法被称为OK,但DataContractSerializer.WriteObject生成一个空文档.

如何使用预共享字典?

提前致谢!

PS我不想搞乱XmlBinaryReaderSession/XmlBinaryWriterSession:我没有"会话",而是我有一个10 GB +数据库同时被许多线程访问.我想要的只是静态预定义字典.

更新:好的我已经发现我只需要调用"XmlDictionaryWriter.Flush".唯一剩下的问题是 - 为什么系统提供的IXmlDictionary实现不能按预期工作?

Avr*_*ram 0

对于 XmlDictionaryWriter,您需要使用会话。
例子

   private static Stream SerializeBinaryWithDictionary(Person person,DataContractSerializer serializer)
    {
        var stream = new MemoryStream();
        var dictionary = new XmlDictionary();
        var session = new XmlBinaryWriterSession();
        var key = 0;
        session.TryAdd(dictionary.Add("FirstName"), out key);
        session.TryAdd(dictionary.Add("LastName"), out key);
        session.TryAdd(dictionary.Add("Birthday"), out key);
        session.TryAdd(dictionary.Add("Person"), out key);
        session.TryAdd(dictionary.Add("http://www.friseton.com/Name/2010/06"),out key);
        session.TryAdd(dictionary.Add("http://www.w3.org/2001/XMLSchema-instance"),out key);

        var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, session);
        serializer.WriteObject(writer, person);
        writer.Flush();
        return stream;
    }
Run Code Online (Sandbox Code Playgroud)