I am using code like this to define protobuf-net schema at runtime. And i am getting error in:
CustomAttributeBuilder contractMem = new CustomAttributeBuilder(
contractMemInfoCon, new object[] { index });
as "Value cannot be null". Please help me to resolve this.
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);
}
Ultimately, the problem comes from here:
This will only work when
oField.DataType
isint
, since the only single-parameterProtoContractAttribute
constructor is the one that takesint tag
. For any otheroField.DataType
, thisGetConstructor
call will returnnull
. An immediate fix would be to usetypeof(int)
each time there, rather thanoField.DataType
.However, frankly I don't think that meta-programming is the right approach for you to use in this scenario (although it is hard to say without a complete example). If you already have an object model, many things can be configured using the
RuntimeTypeModel
/MetaType
/ValueMember
APIs. I don't know how well that would apply to your specific scenario.If you are specifically looking at serializing a
DataSet
, then the "right" approach might depend on whether it is a "typed" data-set, vs a non-typed data-set. Frankly, the first thing I would say is:but I acknowledge that there are some (limited) scenarios where they are genuinely useful. They shouldn't be your default data access technology. If you have to use data-sets (
DataSet
), note that there already is an optimized serialization format built in - it just isn't enabled by default. If you have testedDataSet
using inbuilt .NET serialization and found it unsatisfying, try setting:and re-run your test. This is much more efficient than the default xml format, and might be enough to avoid having to convince
DataSet
to play-nicely with an additional serializer.