我有一个类似于此的类层次结构。这些类包含我已排除的许多其他细节。这是一个简化,专注于这些类的序列化方面。
[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]。例如:
[ProtoInclude(1, typeof(W)]
[ProtoInclude(2, typeof(X)]
[ProtoInclude(3, typeof(Y)]
[ProtoInclude(4, typeof(Z)]
问题是,如何部署这150个ProtoIncludes?我尝试了各种似乎合乎逻辑的组合,但是我会得到各种例外,具体取决于哪些属性存在于哪里。在上面的例子中实际需要序列化的类型是W,X,Y,Z,只有大约150个。
protobuf-net甚至可以处理这样的事情,还是应该尝试其他类型的序列化?
答案 0 :(得分:0)
我不是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
}
}
答案 1 :(得分:0)
行;随着更新的问题,我理解了一点。我希望对象模型中间的泛型确实会让生活变得“有趣”。它不能“开箱即用”;我看看是否有一些简单的调整我可以支持它,但它开始变得丑陋很快。我希望如果可能的话,在中间简单地删除对泛型的需求会更好 - 也许保留一个通用的接口(而不是泛型类)。这是 工作的一些代码;这如何映射到你的代码...我不能100%告诉你。请注意,您不必使用TypeDescriptor
内容(等等) - 因为您使用的是代码生成,这可能会使某些事情变得更容易......
(我没有查看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
{
}