Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 219
ashwnacharya Avatar asked Oct 05 '10 09:10

ashwnacharya


People also ask

Can we create a class dynamically in C#?

You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.

How do you create a dynamic object class?

In C++, the objects can be created at run-time. C++ supports two operators new and delete to perform memory allocation and de-allocation. These types of objects are called dynamic objects. The new operator is used to create objects dynamically and the delete operator is used to delete objects dynamically.

How do I create a dynamic class in Python?

Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. The above syntax returns the type of object.

Can we create dynamic class in Java?

Dynamic Class creation enables you to create a Java class on the fly at runtime, from source code created from a string. Dynamic class creation can be used in extremely low latency applications to improve performance.


2 Answers

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);         }     } } 
like image 160
danijels Avatar answered Sep 25 '22 17:09

danijels


It will take some work, but is certainly not impossible.

What I have done is:

  • Create a C# source in a string (no need to write out to a file),
  • Run it through the Microsoft.CSharp.CSharpCodeProvider (CompileAssemblyFromSource)
  • Find the generated Type
  • And create an instance of that Type (Activator.CreateInstance)

This way you can deal with the C# code you already know, instead of having to emit MSIL.

But this works best if your class implements some interface (or is derived from some baseclass), else how is the calling code (read: compiler) to know about that class that will be generated at runtime?

like image 26
Hans Kesting Avatar answered Sep 24 '22 17:09

Hans Kesting