需要在c#中使用protobuf.net序列化/反序列化数据集

时间:2017-07-31 05:41:33

标签: c# serialization protobuf-net typebuilder

我正在使用这样的代码在运行时定义protobuf-net模式。我在收到错误:

CustomAttributeBuilder contractMem = new CustomAttributeBuilder(
    contractMemInfoCon, new object[] { index });

as“Value not not null”。请帮我解决这个问题。

AssemblyName oAssemblyName = new AssemblyName();
oAssemblyName.Name = "TEST";
AssemblyBuilder oAssmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly("Test", AssemblyBuilderAccess.Run);
ModuleBuilder oModule = oAssmBuilder.DefineDynamicModule("TestModule.Module");


TypeBuilder oTypeBuilder = oModule.DefineType("TestType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);

ConstructorBuilder constructor = oTypeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

//For Defining protocontract                   
ConstructorInfo contractInfoCon = typeof(ProtoBuf.ProtoContractAttribute).GetConstructor(new Type[0]);

CustomAttributeBuilder cab = new CustomAttributeBuilder(contractInfoCon,  new object[0]);

oTypeBuilder.SetCustomAttribute(cab);
string sDataType = "", sPropertyName = "";
int index = 0;
//oFields contains SP columns
foreach (Types.Field oField in oFields)
{
    sPropertyName = oField.ID;
    sDataType = oField.DataType;
    index = index + 1;

    FieldBuilder field = oTypeBuilder.DefineField(sPropertyName, oField.DataType, FieldAttributes.Public);

    PropertyBuilder property =
    oTypeBuilder.DefineProperty("_" + sPropertyName,
             System.Reflection.PropertyAttributes.None,
             oField.DataType,
             new Type[] { oField.DataType });

    MethodAttributes GetSetAttr = MethodAttributes.Public |     MethodAttributes.HideBySig;

    MethodBuilder currGetPropMthdBldr =
    oTypeBuilder.DefineMethod("get_value",
                   GetSetAttr,
                   oField.DataType,
                   Type.EmptyTypes);

    ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
    currGetIL.Emit(OpCodes.Ldarg_0);
    currGetIL.Emit(OpCodes.Ldfld, field);
    currGetIL.Emit(OpCodes.Ret);

    MethodBuilder currSetPropMthdBldr =
    oTypeBuilder.DefineMethod("set_value",
                   GetSetAttr,
                   null,
                   new Type[] { oField.DataType });

    ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
    currSetIL.Emit(OpCodes.Ldarg_0);
    currSetIL.Emit(OpCodes.Ldarg_1);
    currSetIL.Emit(OpCodes.Stfld, field);
    currSetIL.Emit(OpCodes.Ret);

    property.SetGetMethod(currGetPropMthdBldr);
    property.SetSetMethod(currSetPropMthdBldr);

    ConstructorInfo contractMemInfoCon = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(new [] { oField.DataType });
    CustomAttributeBuilder contractMem = new CustomAttributeBuilder(contractMemInfoCon, new object[] { index });
    property.SetCustomAttribute(contractMem);
}

1 个答案:

答案 0 :(得分:1)

最终,问题来自:

ConstructorInfo contractMemInfoCon = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(
    new [] { oField.DataType });

这仅在oField.DataTypeint时才有效,因为唯一的单参数ProtoContractAttribute构造函数是int tag的构造函数。对于任何其他oField.DataType,此GetConstructor来电将返回null。立即解决的问题是每次使用typeof(int),而不是oField.DataType

但是,坦率地说,我不认为元编程是您在这种情况下使用的正确方法(尽管没有完整的例子很难说)。如果已经拥有对象模型,则可以使用RuntimeTypeModel / MetaType / ValueMember API配置许多内容。我不知道这对你的具体情况有多好。

如果您特别关注序列化DataSet,那么"对"方法可能取决于它是否是"打字"数据集,与非类型数据集。坦率地说,第一个我想说的是:

  

停止使用数据集

但我承认有一些(有限)场景,它们真正有用。它们不应该是您的默认数据访问技术。如果 使用数据集(DataSet),请注意已经 内置的优化序列化格式 - 它只是默认情况下没有启用。如果您使用内置的.NET序列化测试DataSet并发现它不满意,请尝试设置:

yourDataSet.RemotingFormat = SerializationFormat.Binary;

重新运行测试。这比默认的xml格式更有效 ,并且可能足以避免说服DataSet与其他序列化程序很好地协作。