这是我在这里发表的第一篇文章,所以请耐心等待......
我正在尝试嵌套多个Generic对象,然后使用ProtoBuf-net将它们传递给WCF。我已经实现了很多(10+)个主要对象,我列出的代码只会显示2.它们都有相似的结构,但是有一些只使用一个或两个泛型(因此它们的继承结构)< / p>
在完成所有标记和ProtoIncludes之后,我已经能够获得一个序列化的主要对象。当我开始处理下一个对象时,我收到了错误:
Known-type mainBase`2 for ProtoIncludeAttribute must be a direct subclass of mainBase`1
将我的大脑放置几个小时后(并在这里阅读)我绝望了,并开始尝试一些随机的东西。当我删除原始主对象的ProtoInclude
并且只为第二个删除它们时,它工作正常!
在下面的代码中,我仍然实现了所有标记,以便您可以获得异常,但是如果您在所有4个aMain
类中注释掉bMain
或mainBase
,该程序将能够序列化当前标记的任何一个。
(我提前道歉,代码很大,但我还没有发现像我这样复杂的问题)
class Program
{
static void Main(string[] args)
{
var vcc = new aMain();
var vccStream = new MemoryStream();
ProtoBuf.Serializer.Serialize(vccStream, vcc);
vccStream.Position = 0;
var newvcc = ProtoBuf.Serializer.Deserialize<aMain>(vccStream);
var vtc = new bMain();
var vtcStream = new MemoryStream();
ProtoBuf.Serializer.Serialize(vtcStream, vtc);
vtcStream.Position = 0;
var newvtc = ProtoBuf.Serializer.Deserialize<bMain>(vtcStream);
}
}
#region Problem Objects, 'Main Objects' Base
[DataContract, ProtoContract, Serializable]
[ProtoInclude(2, typeof(aMain))]
[ProtoInclude(3, typeof(bMain))]
public abstract class mainBase<TbbBase, TaBase, TcbBase>
: mainBase<TbbBase, TaBase>
where TcbBase : cbBase
where TbbBase : bbBase
where TaBase : aBase
{
[DataMember, ProtoMember(1)]
public TcbBase Value3 { get; set; }
protected mainBase()
{
Value3 = Activator.CreateInstance(typeof(TcbBase)) as TcbBase;
}
}
[DataContract, ProtoContract, Serializable]
[ProtoInclude(2, typeof(mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>))]
[ProtoInclude(3, typeof(mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>))]
public abstract class mainBase<TbbBase, TaBase>
: mainBase<TbbBase>
where TbbBase : bbBase
where TaBase : aBase
{
[DataMember, ProtoMember(1)]
public TaBase Value2 { get; set; }
protected mainBase()
{
Value2 = Activator.CreateInstance(typeof(TaBase)) as TaBase;
}
}
[DataContract, ProtoContract, Serializable]
[ProtoInclude(2, typeof(mainBase<aMainSub_bbBase, aMainSub_aBase>))]
[ProtoInclude(3, typeof(mainBase<bMainSub_bbBase, bMainSub_aBase>))]
public abstract class mainBase<TbbBase> : mainBase
where TbbBase : bbBase
{
[DataMember, ProtoMember(1)]
public TbbBase Value1 { get; set; }
protected mainBase()
{
Value1 = Activator.CreateInstance(typeof(TbbBase)) as TbbBase;
}
}
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(mainBase<aMainSub_bbBase>))]
[ProtoInclude(2, typeof(mainBase<bMainSub_bbBase>))]
public abstract class mainBase
{
public abstract string MyDefaultNameSpace { get; }
}
#endregion
#region Main Objects
[DataContract, ProtoContract, Serializable]
public class aMain : mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>
{
public override string MyDefaultNameSpace { get { return "VideoChunker"; } }
}
[DataContract, ProtoContract, Serializable]
public class aMainSub_bbBase : bbbbBase { }
[DataContract, ProtoContract, Serializable]
public class aMainSub_aBase : aaBase { }
[DataContract, ProtoContract, Serializable]
public class aMainSub_cbBase : cbBase { }
[DataContract, ProtoContract, Serializable]
public class bMain : mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>
{
public override string MyDefaultNameSpace { get { return "VideoTranscoder"; } }
}
[DataContract, ProtoContract, Serializable]
public class bMainSub_bbBase : bbbbBase { }
[DataContract, ProtoContract, Serializable]
public class bMainSub_aBase : aaBase { }
[DataContract, ProtoContract, Serializable]
public class bMainSub_cbBase : cbBase { }
#endregion
#region Base Objects
[DataContract, ProtoContract, Serializable]
[ProtoInclude(2, typeof(aMainSub_bbBase))]
[ProtoInclude(3, typeof(bMainSub_bbBase))]
public abstract class bbbbBase : bbbBase { }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(bbbbBase))]
public abstract class bbbBase : bbBase { }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(bbbBase))]
public abstract class bbBase : bBase { public override string GetConfigNamespace { get { return ".Service"; } } }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(bbBase))]
[ProtoInclude(2, typeof(cbBase))]
public abstract class bBase : subBase { }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(aMainSub_cbBase))]
[ProtoInclude(2, typeof(bMainSub_cbBase))]
public class cbBase : bBase { public override string GetConfigNamespace { get { return ".Fabric"; } } }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(bBase))]
[ProtoInclude(4, typeof(aBase))]
public abstract class subBase { public virtual string GetConfigNamespace { get { return string.Empty; } } }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(2, typeof(aMainSub_aBase))]
[ProtoInclude(3, typeof(bMainSub_aBase))]
public abstract class aaBase : aBase { }
[DataContract, ProtoContract, Serializable]
[ProtoInclude(1, typeof(aaBase))]
public abstract class aBase : subBase { public override string GetConfigNamespace { get { return ".Action"; } } }
#endregion
由于我使用的是旧版本的protobuf,我决定取消它的来源,看看我是否可以解决任何问题。经过一些调试后,我发现了抛出异常的地方,我只是做了continue;
而不是抛出异常。
在文件SerializerT.cs
中,第246行如下:
foreach (ProtoIncludeAttribute pia in Attribute.GetCustomAttributes(typeof(T), typeof(ProtoIncludeAttribute), false))
{
Type subclassType = pia.ResolveKnownType(typeof(T).Assembly);
if (subclassType == null)
{
throw new ProtoException("Unable to identify known-type for ProtoIncludeAttribute: " + pia.KnownTypeName);
}
if (subclassType.BaseType != typeof(T))
{
continue;
throw new ProtoException(string.Format(
"Known-type {0} for ProtoIncludeAttribute must be a direct subclass of {1}",
subclassType.Name, typeof(T).Name));
}
Property<T, T> prop;
switch (pia.DataFormat)
{
case DataFormat.Default:
prop = (Property<T, T>) PropertyUtil<T>.CreateTypedProperty("CreatePropertyMessageString", typeof(T), typeof(T), subclassType);
break;
case DataFormat.Group:
prop = (Property<T, T>)PropertyUtil<T>.CreateTypedProperty("CreatePropertyMessageGroup", typeof(T), typeof(T), subclassType);
break;
default:
throw new ProtoException("Invalid ProtoIncludeAttribute data-format: " + pia.DataFormat);
}
// check for duplicates
if (tagsInUse.Contains(pia.Tag))
{
throw new InvalidOperationException(
string.Format("Duplicate tag {0} detected in sub-type {1}", pia.Tag, subclassType.Name));
}
tagsInUse.Add(pia.Tag);
prop.Init(pia.Tag, pia.DataFormat, PropertyFactory.GetPassThru<T>(), null, true, null);
subclassList.Add(new KeyValuePair<Type, Property<T, T>>(subclassType, prop));
}
您可以看到continue'
位于原始throw
正上方的位置。我不确定这个行动的后果是什么;这是一个真正的错误,还是我打开了一些灾难性的疯狂?
感谢您的时间。
答案 0 :(得分:0)
好吧,我想我现在理解这个模型(非常高兴我昨晚看起来不太努力; p) - 你有:
aMain
: mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>
: mainBase<aMainSub_bbBase, aMainSub_aBase>
: mainBase<aMainSub_bbBase> : mainBase
bMain
: mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>
: mainBase<bMainSub_bbBase, bMainSub_aBase>
: mainBase<bMainSub_bbBase> : mainBase
aMainSub_bbBase, bMainSub_bbBase
: bbbbBase : bbbBase : bbBase : bBase : subBase
aMainSub_aBase, bMainSub_aBase
: aaBase : aBase : subBase
aMainSub_cbBase, bMainSub_cbBase
: cbBase : bBase : subBase
这实际上是与this question类似的问题,与属性相关,因为属性适用于所有封闭类型,而不仅仅是你在考虑。特别是,您目前告诉aMain
与 mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>
和 mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>
相关联({1}}对于那里的所有交叉都是一样的。
在短时间内有两个类似的问题,我会试着看一下这个问题,但短期内我认为v2建模器是解决这个问题的方法。我已从3种通用类型(ProtoInclude
,mainBase<>
和mainBase<,>
)中删除了mainBase<,,>
属性,然后:
var model = RuntimeTypeModel.Default;
model[typeof(mainBase<aMainSub_bbBase>)].AddSubType(2, typeof(mainBase<aMainSub_bbBase, aMainSub_aBase>));
model[typeof(mainBase<bMainSub_bbBase>)].AddSubType(2, typeof(mainBase<bMainSub_bbBase, bMainSub_aBase>));
model[typeof(mainBase<aMainSub_bbBase, aMainSub_aBase>)].AddSubType(2, typeof(mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>));
model[typeof(mainBase<bMainSub_bbBase, bMainSub_aBase>)].AddSubType(2, typeof(mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>));
model[typeof(mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>)].AddSubType(2, typeof(aMain));
model[typeof(mainBase<bMainSub_bbBase, bMainSub_aBase, bMainSub_cbBase>)].AddSubType(2, typeof(bMain));
(常规属性处理大多数情况)
请注意,由于我们位于 parallel 分支中,因此它不需要单独的2
/ 3
标记,因为它不是您希望 aMain
或bMain
来自mainBase<aMainSub_bbBase, aMainSub_aBase, aMainSub_cbBase>
- 只能aMain
。
我将不得不调查使这个更干净的选项 - 但至少在v2中它可以工作!
重新删除现有的异常;老实说,我不相信v1代码具有正确处理这种情况的微妙之处。删除该异常可能会导致其以其他有趣的方式失败,特别是当它尝试解决类型层次结构时。无论如何都要对你的本地副本做出任何改变,但是:冒着自己的风险 - 我不能说“是的,这是安全的”,因为我不相信它。我的建议是在v2中使用更复杂的建模,同时我研究处理这种类型的并行通用模型的方法。这里的任何更改都只适用于v2,因为v1根本没有理解存储此信息的方法,而基本上没有引入v2类型建模器,即将v1转换为v2。