How to create a runtime class?

Asked

Viewed 924 times

2

How to create a runtime class, or Runtime, dynamically, from a Dictionary<TKey, TValue>, for example, with C#?

Dictionary<string, string> dicionario = new Dictionary<string, string>();
dicionario.Add("nome", "string");
dicionario.Add("idade", "int");
dicionario.Add("telefone", "string");
dicionario.Add("cpf", "string");

The TKey would be the name of the properties to be created in the class, already the TValue, would be the kind.

  • Dynamic or static class? What version of C# are you using?

  • You accepted an answer that generates a static, so I didn’t understand.

1 answer

6


Short answer: using System.Reflection.Emit.

Long answer: Is this answer here, but I won’t just stick it to you here. I’ll explain the principle.

First you need to define the dynamic type builder. The answer defines it below (I modified it a little with some things):

private static TypeBuilder GetTypeBuilder(string libraryName = "MainModule", string typeSignature = "MyDynamicType")
{
    var an = new AssemblyName(typeSignature); // Aqui você vai definir o nome da classe dinâmica
    AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(libraryName); // Aqui vai definir em qual Class Library sua classe dinâmica vai estar

    TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
            TypeAttributes.Public |
            TypeAttributes.Class |
            TypeAttributes.AutoClass |
            TypeAttributes.AnsiClass |
            TypeAttributes.BeforeFieldInit |
            TypeAttributes.AutoLayout,
            null);
    return tb;
}

Next, we can put the method that creates properties. It needs the TypeBuilder previously assembled for operation:

private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
    FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

    PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
    MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
    ILGenerator getIl = getPropMthdBldr.GetILGenerator();

    getIl.Emit(OpCodes.Ldarg_0);
    getIl.Emit(OpCodes.Ldfld, fieldBuilder);
    getIl.Emit(OpCodes.Ret);

    MethodBuilder setPropMthdBldr =
        tb.DefineMethod("set_" + propertyName,
          MethodAttributes.Public |
          MethodAttributes.SpecialName |
          MethodAttributes.HideBySig,
          null, new[] { propertyType });

    ILGenerator setIl = setPropMthdBldr.GetILGenerator();
    Label modifyProperty = setIl.DefineLabel();
    Label exitSet = setIl.DefineLabel();

    setIl.MarkLabel(modifyProperty);
    setIl.Emit(OpCodes.Ldarg_0);
    setIl.Emit(OpCodes.Ldarg_1);
    setIl.Emit(OpCodes.Stfld, fieldBuilder);

    setIl.Emit(OpCodes.Nop);
    setIl.MarkLabel(exitSet);
    setIl.Emit(OpCodes.Ret);

    propertyBuilder.SetGetMethod(getPropMthdBldr);
    propertyBuilder.SetSetMethod(setPropMthdBldr);
}

You will probably have to modify your dictionary to receive one Type instead of string.

The following is the method that compiles the dictionary in the dynamic class:

public static Type CompileResultType(Dictionary<string, Type> dicionario) // Repare que já mudei aqui pra você
{
    TypeBuilder tb = GetTypeBuilder(); // Aqui constrói a classe num Assembly "MainModule.dll", classe "MyDynamicType". 
                                       // Parametrize da forma que achar melhor. 
    ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

    foreach (KeyValuePair<string, Type> chaveValor in dicionario)
        CreateProperty(tb, chaveValor.Key, chaveValor.Value);

    Type objectType = tb.CreateType();
    return objectType;
}

Finally, the static method that invokes all others:

public static object CreateNewObject(Dictionary<string, Type> dicionario)
{
    var myType = CompileResultType(dicionario);
    return Activator.CreateInstance(myType);
}

Use:

var meuObjetoCriadoDiamicamente = MyTypeBuilder.CreateNewObject(dicionario);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.