protobuf的泛型类的层次结构属性 [英] Protobuf attributes with a hierarchy of generic classes

查看:397
本文介绍了protobuf的泛型类的层次结构属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类层次结构,看起来像这样。这些类包含了很多,我已经排除其他细节。这是着眼于这些类的序列化方面的简化

I have a class hierarchy that looks like this. These classes contain a lot of other details which I have excluded. This is a simplification to focus on the serialization aspect of these classes.

[ProtoInclude(1, typeof(Query<bool>))]
[ProtoInclude(2, typeof(Query<string>))]
[ProtoInclude(3, typeof(Query<int>))]
[ProtoInclude(4, typeof(Query<decimal>))]
[ProtoInclude(5, typeof(Query<DataSet>))]
abstract class Query
{
    public string Result { get; set; }
}
[ProtoInclude(1, typeof(SpecialQuery)]
abstract class Query<T> : Query
{
    public new T Result { get; set; }
}
abstract class SpecialQuery : Query<DataSet>
{
    public new string Result { get; set; }
}

我也有通用的查询大约150自动生成的后裔,拥有种类繁多的泛型类型的,例如:

I also have about 150 auto-generated descendants of generic Query, with a large variety of generic types. For example:

[ProtoContract]
class W : Query<bool>
{
}
[ProtoContract]
class X : Query<string>
{
}
[ProtoContract]
class Y : Query<int>
{
}
[ProtoContract]
class Z : SpecialQuery
{
}

我也自动生成[ProtoInclude]所有这些类型,例如:

I've also autogenerated [ProtoInclude] for all those types. For example:

[ProtoInclude(1, typeof(W)]
[ProtoInclude(2, typeof(X)]
[ProtoInclude(3, typeof(Y)]
[ProtoInclude(4, typeof(Z)]

现在的问题是,我该如何部署这些150 ProtoIncludes?我试过,似乎合乎逻辑的各种组合,但我得到这取决于属性各种异常都存在哪里。是实际的类型需要在上面的例子中的序列将是W,X,Y,Z,只有其中约150

The question is, how do I deploy those 150 ProtoIncludes? I've tried various combinations that seem logical, but I get various exceptions depending on which attributes are present where. The types that are actually need serialization in the above example would be W, X, Y, Z, only there's about 150 of them.

能否protobuf网甚至处理这样的事情,或者我应该尝试一些其他类型的系列化

Can protobuf-net even deal with something like this, or should I try some other kind of serialization?

推荐答案

OK?;与更新的问题,据我了解多一点。我期望在对象模型中间的仿制药确实打算让生活......好玩。它不工作开箱即用;我看了看是否有一些简单的调整,我可以做,以支持它,但它开始变得丑陋很快。我希望这将是更好的只是删除的一般需要在中间,如果可能的话 - 也许保留了通用的接口(而不是普通类)。下面是一些代码,确实的工作;如何映射到你的代码......我不能告诉100%。注意:您不必使用 TypeDescriptor 的东西(ETC) - 它只是似乎因为你正在使用代码生成,这可能让一些事情变得更容易...

OK; with the updated question I understand a bit more. I expect the generics in the middle of the object-model are indeed going to make life... "fun". It doesn't work "out of the box"; I looked to see if there were some simple tweaks I could make to support it, but it started getting ugly pretty quickly. I expect it would be better to simply remove the need for the generic in the middle, if possible - perhaps retaining a generic interface (rather than the generic class). Here's some code that does work; how this maps to your code... I can't tell 100%. Note you don't have to use the TypeDescriptor stuff (etc) - it just seemed that since you are using code-gen this might make some things easier...

(我没有检查的DataSet 的东西 - 仅仅是类的东西)

(I didn't check the DataSet stuff - just the class stuff)

using System;
using System.ComponentModel;
using System.Data;
using System.IO;
using NUnit.Framework;
using ProtoBuf;

[TestFixture]
public class ComplexGenericTest
{
    [Test]
    public void TestX()
    {
        Query query = new X { Result = "abc" };
        Assert.AreEqual(typeof(string), query.GetQueryType());
        Query clone = Serializer.DeepClone<Query>(query);
        Assert.IsNotNull(clone);
        Assert.AreNotSame(clone, query);
        Assert.IsInstanceOfType(query.GetType(), clone);
        Assert.AreEqual(((X)query).Result, ((X)clone).Result);
    }
    [Test]
    public void TestY()
    {
        Query query = new Y { Result = 1234};
        Assert.AreEqual(typeof(int), query.GetQueryType());
        Query clone = Serializer.DeepClone<Query>(query);
        Assert.IsNotNull(clone);
        Assert.AreNotSame(clone, query);
        Assert.IsInstanceOfType(query.GetType(), clone);
        Assert.AreEqual(((Y)query).Result, ((Y)clone).Result);
    }

}
public static class QueryExt {
    public static Type GetQueryType(this IQuery query)
    {
        if (query == null) throw new ArgumentNullException("query");
        foreach (Type type in query.GetType().GetInterfaces())
        {
            if (type.IsGenericType
                && type.GetGenericTypeDefinition() == typeof(IQuery<>))
            {
                return type.GetGenericArguments()[0];
            }
        }
        throw new ArgumentException("No typed query implemented", "query");
    }
}
public interface IQuery
{
    string Result { get; set; }
}
public interface IQuery<T> : IQuery
{
    new T Result { get; set; }
}

[ProtoInclude(21, typeof(W))]
[ProtoInclude(22, typeof(X))]
[ProtoInclude(23, typeof(Y))]
[ProtoInclude(25, typeof(SpecialQuery))]
[ProtoContract]
abstract class Query : IQuery
{
    public string Result
    {
        get { return ResultString; }
        set { ResultString = value; }
    }
    protected abstract string ResultString { get; set; }

    // these are to allow simple ResultString implementations
    // without the codegen having to worry about int.Parse etc
    protected static string FormatQueryString<T>(T value)
    {
        return TypeDescriptor.GetConverter(typeof(T))
            .ConvertToInvariantString(value);
    }
    protected static T ParseQueryString<T>(string value)
    {
        return (T) TypeDescriptor.GetConverter(typeof(T))
            .ConvertFromInvariantString(value);
    }
}
[ProtoContract]
[ProtoInclude(21, typeof(Z))]
abstract class SpecialQuery : Query, IQuery<DataSet>
{

    public new DataSet Result { get; set; }

    [ProtoMember(1)]
    protected override string ResultString
    {
        get {
            if (Result == null) return null;
            using (StringWriter sw = new StringWriter())
            {
                Result.WriteXml(sw, XmlWriteMode.WriteSchema);
                return sw.ToString();
            }
        }
        set {
            if (value == null) { Result = null; return; }
            using (StringReader sr = new StringReader(value))
            {
                DataSet ds = new DataSet();
                ds.ReadXml(sr, XmlReadMode.ReadSchema);
            }
        }
    }
}

[ProtoContract]
class W : Query, IQuery<bool>
{
    [ProtoMember(1)]
    public new bool Result { get; set; }

    protected override string ResultString
    {
        get {return FormatQueryString(Result); }
        set { Result = ParseQueryString<bool>(value); }
    }
}
[ProtoContract]
class X : Query, IQuery<string>
{
    [ProtoMember(1)]
    public new string Result { get; set; }

    protected override string ResultString
    {
        get { return Result ; }
        set { Result = value; }
    }
}
[ProtoContract]
class Y : Query, IQuery<int>
{
    [ProtoMember(1)]
    public new int Result { get; set; }

    protected override string ResultString
    {
        get { return FormatQueryString(Result); }
        set { Result = ParseQueryString<int>(value); }
    }
}
[ProtoContract]
class Z : SpecialQuery
{
}

这篇关于protobuf的泛型类的层次结构属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆