因此,我正在为Unity3D编写自定义序列化系统,以便用户实现和选择不同的序列化。我目前支持BinaryFormatter
和protobuf-net
。然而;在这个系统中,我有序列化的持久自定义规则,我希望我的序列化程序可以很好地使用:
[Serializable]
[Save]
,[Serialize]
和[SerializeField]
现在我想调整我的protobuf-net模型以适应这些规则,因此我不必使用任何protobufs自定义属性,如ProtoContract
,ProtoMember
等
我认为我可以做到这一点的方法是,有一个可序列化类型的数组,用户可以添加他的自定义类型(这样他就不需要那些类型的ProtoContract) - 我会迭代这些键入并将它们添加到我的模型中。 Foreach类型,我会得到满足我的序列化规则的成员,并将它们添加到模型中。
我还想说的另一件事就是说你有一个抽象的课程A
,其中有孩子B
和C
,用户不必明确添加{{ 1}}和B
,他们只需添加C
,我就会得到A
个孩子并自行添加。
我的问题归结为:而不是用户必须写这个:
A
我希望他们能够写下这个:
[ProtoContract]
[ProtoInclude(1, typeof(Child1))]
[ProtoInclude(2, typeof(Child2))]
public abstract class AbstractBase
{
public abstract int Num { get; set; }
}
[ProtoContract]
public class Child1 : AbstractBase
{
[ProtoMember(1)]
public int x;
public override int Num { get { return x; } set { x = value; } }
}
[ProtoContract]
public class Child2 : AbstractBase
{
[ProtoMember(1)]
public int y;
[ProtoMember(2)]
public int z;
public override int Num { get { return y; } set { y = value; } }
}
这是我尝试的内容:
[Serializble]
public abstract class AbstractBase
{
public abstract int Num { get; set; }
}
[Serializble]
public class Child1 : AbstractBase
{
public int x;
public override int Num { get { return x; } set { x = value; } }
}
[Serializble]
public class Child2 : AbstractBase
{
public int y;
public int z;
public override int Num { get { return y; } set { y = value; } }
}
// ProtobufSerializableTypes.cs
public static Type[] SerializableTypes = new[]
{
typeof(AbstractBase)
};
所以我尝试将所有必需的类型添加到模型中,将所有子类型添加到父类型,然后迭代所有添加的类型,并向模型添加适当的字段/属性(对应于我的序列化规则)从那种类型
然而,这是失败的:
[TestClass]
public class ProtobufDynamicSerializationTestSuite
{
private AbstractBase Base { get; set; }
private Type[] SerializableTypes { get; set; }
[TestInitialize]
public void Setup()
{
Base = new Child1();
SerializableTypes = new[]
{
typeof(AbstractBase)
};
}
[TestMethod]
public void ShouldCopyWithCustomConfig()
{
var model = TypeModel.Create();
Func<Type, MetaType> addType = type =>
{
log("adding type: {0}", type.Name);
return model.Add(type, false);
};
var hierarchy = new Dictionary<MetaType, List<Type>>();
for (int i = 0; i < SerializableTypes.Length; i++)
{
var type = SerializableTypes[i];
var meta = addType(type);
var temp = new List<Type>();
var children = type.Assembly.GetTypes().Where(t => t.IsSubclassOf(type) && !t.IsAbstract).ToList();
for(int j = 0; j < children.Count; j++)
{
var child = children[j];
addType(child);
log("adding subtype {0} with id {1}", child.Name, j + 1);
meta.AddSubType(j + 1, child);
temp.Add(child);
}
hierarchy[meta] = temp;
}
Func<Type, string[]> getMemberNames = x =>
//SerializationLogic.GetSerializableMembers(x, null) // real logic
x.GetMembers(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public) // dummy logic
.Where(m => m.MemberType == MemberTypes.Field)
.Select(m => m.Name)
.ToArray();
foreach (var entry in hierarchy)
{
int id = 1;
foreach (var type in entry.Value)
{
foreach (var member in getMemberNames(type))
{
log("adding member {0} to type {1} with id {2}", member, type.Name, id);
entry.Key.Add(id++, member);
}
}
}
Base.Num = 10;
var copy = (AbstractBase)model.DeepClone(Base);
Assert.AreEqual(copy.Num, 10);
}
void log(string msg, params object[] args)
{
Console.WriteLine(string.Format(msg, args));
}
void log(string msg)
{
log(msg, new object[0]);
}
}
我做错了什么?还有更好的方法吗?
谢谢!
请注意,最初我没有这个字典步骤,我尝试在将其添加到模型后立即添加类型的成员,但如果我说,键入Test Name: ShouldCopyWithCustomConfig
Test Outcome: Failed
Result Message:
Test method ProtobufTests.ProtobufDynamicSerializationTestSuite.ShouldCopyWithCustomConfig threw exception:
System.ArgumentException: Unable to determine member: x
Parameter name: memberName
Result StandardOutput:
adding type: AbstractBase
adding type: Child1
adding subtype Child1 with id 1
adding type: Child2
adding subtype Child2 with id 2
adding member x to type Child1 with id 1
,则会失败和A
,B
有一个A
引用,如果我尝试添加类型B
及其成员,我会来A
protobuf无法在这个阶段识别,因为它尚未添加到模型中......所以我认为有必要先添加类型,然后再添加其成员......
答案 0 :(得分:1)
主要问题似乎是entry.Key
指的是基类型,但是你试图描述特定子类型的成员;这就是我的所作所为:
foreach (var entry in hierarchy)
{
foreach (var type in entry.Value)
{
var meta = model.Add(type, false);
var members = getMemberNames(type);
log("adding members {0} to type {1}",
string.Join(",", members), type.Name);
meta.Add(getMemberNames(type));
}
}
我还添加了一些严格的顺序:
.OrderBy(m => m.Name) // in getMemberNames
和
.OrderBy(x => x.FullName) // in var children =
确保id至少是可预测的。注意,在protobuf中,id非常重要:不严格定义id的结果是,如果有人将AardvarkCount
添加到模型中,它可以抵消所有id,并打破现有数据的反序列化。需要注意的事项。