blfuentes
blfuentes

Reputation: 2827

How to create a class dynamicaly

I am trying to generate a class dinamicaly through a List of dictionaries with the following code:

public static object CreateCustomObject(List<Dictionary<string, string>> fileProperties)
{
    object result = null;
    
    // create the assembly and module
    AssemblyName assemblyName = new AssemblyName();
    assemblyName.Name = "tmpAssembly";
    AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpAssembly");
    
    // create a new type builder
    TypeBuilder typeBuilder = module.DefineType("CustomObjectToSerialize", TypeAttributes.Public | TypeAttributes.Class);
    
    foreach (Dictionary<string, string> _property in fileProperties)
    {
        foreach (var _elem in _property)
        {
            // create property from file      
            string propertyName = _elem.Key.Replace('.', '_');
            FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
            PropertyBuilder property = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, typeof(string), new Type[] { typeof(string) });
    
            MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
    
            MethodBuilder currGetPropMethBldr = typeBuilder.DefineMethod("get_value", GetSetAttr, typeof(string), Type.EmptyTypes);
    
            ILGenerator currGetIL = currGetPropMethBldr.GetILGenerator();
            currGetIL.Emit(OpCodes.Ldarg_0);
            currGetIL.Emit(OpCodes.Ldfld, field);
            currGetIL.Emit(OpCodes.Ret);
    
            MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_value", GetSetAttr, typeof(string), Type.EmptyTypes);
    
            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(currGetPropMethBldr);
            property.SetSetMethod(currSetPropMthdBldr);
        }
    }
    
    Type generatedType = typeBuilder.CreateType();
    result = Activator.CreateInstance(generatedType);
    PropertyInfo[] properties = generatedType.GetProperties();
    
    int propertiesCount = 0;
    
    List<string> values = new List<string>();
    foreach (Dictionary<string, string> _property in fileProperties)
    {
        foreach (var _elem in _property)
        {
            //values.Add(_elem.Value);
            string value = _elem.Value;
            string propName = _elem.Key.Replace('.', '_');
            PropertyInfo pinfo = generatedType.GetProperty(propName);
            //here I get the error
            //'System.Reflection.TargetParameterCountException' occurred in mscorlib.dll
            pinfo.SetValue(result, value);
            //properties[propertiesCount].SetValue(result, value, null);
            //propertiesCount++;
        }
    }
    
    //values.ForEach(_v =>
    //{
    //   properties[propertiesCount].SetValue(result, _v, null);
    //   propertiesCount++;
    //});
    
    return result;
}

I get this error when trying to set the value of the property.:

An unhandled exception of type 'System.Reflection.TargetParameterCountException' occurred in mscorlib.dll Additional information: Parameter count mismatch.

I checked and I have in my sample 3 properties and I will assign 3 values.

The code is taken and Little bit adapted from here

Any idea?

Upvotes: 0

Views: 215

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70701

You have defined the setter method incorrectly. You seem to have copy/pasted from the getter, without correctly modifying the return type and argument list.

While the getter returns a value and has no arguments, a setter returns no value (i.e. is void) and takes one argument.

Instead of what you have in your code, it should look like this:

MethodBuilder currSetPropMthdBldr =
    typeBuilder.DefineMethod("set_value", GetSetAttr, null, new [] { typeof(string) });

Upvotes: 1

Related Questions