سؤال

لدي التسلسل الهرمي للفئة التي تبدو مثل هذا. تحتوي هذه الفصول الدراسية على تفاصيل أخرى مستبعتها. هذه تبسيط التركيز على جانب التسلسل في هذه الفصول.

[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 أحفادا تلقائيا من الاستعلام العام، مع مجموعة كبيرة ومتنوعة من الأنواع العامة. علي سبيل المثال:

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

لقد قمت أيضا باللحظية [البروتوخوخة] لجميع هذه الأنواع. علي سبيل المثال:

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

السؤال هو، كيف يمكنني نشر أولئك 150 البروتينات؟ لقد جربت مجموعات مختلفة تبدو منطقية، لكنني أحصل على استثناءات مختلفة اعتمادا على السمات التي توجد فيها. الأنواع التي تحتاج فعلا إلى التسلسل في المثال أعلاه ستكون W، X، Y، Z، هناك فقط حوالي 150 منهم.

يمكن protobuf- صافي حتى التعامل مع شيء من هذا القبيل، أو يجب أن أحاول نوع آخر من التسلسل؟

هل كانت مفيدة؟

المحلول

نعم؛ مع السؤال المحدث أفهم أكثر قليلا. أتوقع أن تجعل الجنراء في منتصف نموذج الكائن في الواقع حياة ... "متعة". لا يعمل "خارج الصندوق"؛ نظرت إلى معرفة ما إذا كانت هناك بعض التعديلات البسيطة التي يمكنني تقديمها لدعمها، لكنها بدأت بالحصول بسرعة كبيرة. أتوقع أنه سيكون من الأفضل ببساطة إزالة الحاجة إلى الجنرال في الوسط، إن أمكن - ربما احتفظ عام واجهه المستخدم (بدلا من الطبقة العامة). إليك بعض الكود هل الشغل؛ كيف هذه الخرائط إلى التعليمات البرمجية الخاصة بك ... لا أستطيع أن أقول 100٪. ملاحظة ليس لديك لاستخدام TypeDescriptor الاشياء (إلخ) - يبدو ذلك فقط لأنك تستخدم Code-Gen هذا قد يجعل بعض الأشياء أسهل ...

(لم أتحقق من DataSet أشياء - مجرد الاشياء الفئة)

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
{
}

نصائح أخرى

أنا لست متأكدا 100٪ أفهم السيناريو الذي تريد طرازه؛ ومع ذلك، [ProtoInclude] تبدو فقط مستوى واحد من الميراث بعيدا.

إذا فهمت بشكل صحيح، جرب ما يلي؛ لاحظ أنك ستحتاج إلى معرفة الأنواع العامة المحتملة في وقت الترجمة في الوقت الحالي:

using System;
using ProtoBuf;
[ProtoContract]
[ProtoInclude(2, typeof(Response))]
[ProtoInclude(3, typeof(Query))]
class Packet
{
    [ProtoMember(1)]
    int ID;
}
[ProtoContract]
[ProtoInclude(1, typeof(Response<int>))]
[ProtoInclude(2, typeof(Response<decimal>))]
[ProtoInclude(3, typeof(Response<string>))]
class Response : Packet
{
}
[ProtoContract]
class Response<T> : Response
{
    [ProtoMember(2)]
    public T Value;

    public override string ToString()
    {
        return typeof(T).Name + ": " + Value;
    }
}
static class Program
{
    static void Main()
    {
        Packet packet = new Response<int> { Value = 123 };
        Packet clone = Serializer.DeepClone<Packet>(packet);
        Console.WriteLine(clone.ToString()); // should be int/123
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top