Jaycee
Jaycee

Reputation: 3118

Dynamic class creation including dynamic type name

I have a list of strings that needs to be property names and also a string that needs to be the type name. I am passing the object to a third party UI and all it cares about is the class and field names which it displays (default behaviour). I can implement an interface to customize the strings returned so they are not just camel case names and also to hide certain members.

I saw the ExpandOObject and this does not work as the third party cannot find any member names on it as it displays nothing and does not call the method on its interface to replace the field accessors with meaningful names.

The DynamicObject looked more promising but I would unsure how to implement this, and have not seen a simple example.

I suppose there is also TypeBuilder, which I have never used.

Could do with some guidance on getting this Duck type behaviour. I assume the third party does something like GetType().Name by default so this needs to be intercepted. It must use reflection to discover the field names too. It accepts an instance of a type contained within a BindingSource - this is where the field names get read from and the type of course.

Upvotes: 1

Views: 203

Answers (2)

Jaycee
Jaycee

Reputation: 3118

Very helpful suggestions from fejesjoco so thanks and here is the simple, relatively non scary solution using Reflection.Emit.TypeBuilder that I needed:

 var assembly = new AssemblyName("FieldTypes");
 AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
 ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assembly.Name);
 TypeBuilder typeBuilder = moduleBuilder.DefineType("DataObjects", TypeAttributes.Public | TypeAttributes.AutoClass | 
     TypeAttributes.AnsiClass |TypeAttributes.BeforeFieldInit, typeof(System.Object));
 foreach (var dataObject in layout.DatabaseInstance.DataSourceObjects)
 {
     FieldBuilder fieldBuilder = typeBuilder.DefineField(dataObject.TableName + "X", typeof(System.String), FieldAttributes.Private);
     PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(dataObject.TableName, PropertyAttributes.HasDefault, typeof(System.String), null);
     MethodBuilder propertyGetter = typeBuilder.DefineMethod("get_" + dataObject.TableName, MethodAttributes.Public | 
         MethodAttributes.SpecialName |MethodAttributes.HideBySig, typeof(System.String), Type.EmptyTypes);
     ILGenerator randomPropertyGetterIL = propertyGetter.GetILGenerator();
     randomPropertyGetterIL.Emit(OpCodes.Ldarg_0);
     randomPropertyGetterIL.Emit(OpCodes.Ldfld, fieldBuilder);
     randomPropertyGetterIL.Emit(OpCodes.Ret);
     propertyBuilder.SetGetMethod(propertyGetter);
 }
 Type randomType = typeBuilder.CreateType();
 binding.DataSource = Activator.CreateInstance(randomType);

Upvotes: 1

fejesjoco
fejesjoco

Reputation: 11903

If you really, really want to create a dynamic type, you actually can. You start with AppDomain.DefineDynamicAssembly, and then here is this little starting level tutorial: http://msdn.microsoft.com/en-us/library/5kyyyeh2%28v=vs.110%29.aspx , or this more thorough one: http://www.codeproject.com/Articles/121568/Dynamic-Type-Using-Reflection-Emit . Be warned, it's heavy stuff. If you want to add code, you need to emit IL assembly instructions (you need to do that if you want properties). It's not THAT difficult because you can use tools like Reflector to decompile anything into IL and you can just copy that.

Or you can write C# code (as an actual text file or with the CodeDom) and compile that. Here's a hello world sample: http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider%28v=vs.110%29.aspx . It's less hardcore, it may be a little or even a lot easier on your part, but it's doing more work in the background. It will not support all edge cases, all features of the C# language. And it's more indirect, so in contrast to the above solution, you need to handle assembly references and loading the new assembly file yourself.

You didn't say too much about your original problem, or that library, or why you don't know the type and property names in advance. Normally I would try to talk you out of doing this :).

Upvotes: 3

Related Questions