Search code examples
c#.netreflection.emitdynamic-class-creation

How to dynamically create a class?


I have a class which looks like this:

public class Field
{
    public string FieldName;
    public string FieldType;
}

And an object List<Field> with values:

{"EmployeeID","int"},
{"EmployeeName","String"},
{"Designation","String"}

I want to create a class that looks like this:

Class DynamicClass
{
    int EmployeeID,
    String EmployeeName,
    String Designation
}

Is there any way to do this?

I want this to be generated at runtime. I don't want a physical CS file residing in my filesystem.


Solution

  • Yes, you can use System.Reflection.Emit namespace for this. It is not straight forward if you have no experience with it, but it is certainly possible.

    Edit: This code might be flawed, but it will give you the general idea and hopefully off to a good start towards the goal.

    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace TypeBuilderNamespace
    {
        public static class MyTypeBuilder
        {
            public static void CreateNewObject()
            {
                var myType = CompileResultType();
                var myObject = Activator.CreateInstance(myType);
            }
            public static Type CompileResultType()
            {
                TypeBuilder tb = GetTypeBuilder();
                ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
    
                // NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
                foreach (var field in yourListOfFields)
                    CreateProperty(tb, field.FieldName, field.FieldType);
    
                Type objectType = tb.CreateType();
                return objectType;
            }
    
            private static TypeBuilder GetTypeBuilder()
            {
                var typeSignature = "MyDynamicType";
                var an = new AssemblyName(typeSignature);
                AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
                TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
                        TypeAttributes.Public |
                        TypeAttributes.Class |
                        TypeAttributes.AutoClass |
                        TypeAttributes.AnsiClass |
                        TypeAttributes.BeforeFieldInit |
                        TypeAttributes.AutoLayout,
                        null);
                return tb;
            }
    
            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);
            }
        }
    }