views:

150

answers:

1

I'm currently working on creating an Assembly with virtual properties. The examples on MSDN are only creating normal properties. How do I create a class inside an assembly which has virtual properties?

I would like to be able to generate a class like this:

    public class ClassA
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string ClassName { get; set; }
        public virtual ClassB Partner { get; set; }
    }

    public class ClassB
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }

The PropertyBuilder class doesn't have PropertyAttributes.Virtual, so I don't know how to create a virtual property. If I create this class in Visual Studio myself, and then open it in Reflector, the properties themselfes are virtual, so it is possible.

How can it be done?

+1  A: 

Here's an example of creating a class at runtime that contains a single integer property Id which is virtual:

class Program
{
    static void Main(string[] args)
    {
        var aName = new AssemblyName("DynamicAssemblyExample");
        var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
        var mb = ab.DefineDynamicModule(aName.Name);
        var tb = mb.DefineType("MyDynamicType", TypeAttributes.Public);
        var fbId = tb.DefineField("_id", typeof(int), FieldAttributes.Private);
        var pbId = tb.DefineProperty("Id", PropertyAttributes.HasDefault, typeof(int), null);

        var getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;

        var mbIdGetAccessor = tb.DefineMethod("get_Id", getSetAttr, typeof(int), Type.EmptyTypes);

        var numberGetIL = mbIdGetAccessor.GetILGenerator();
        numberGetIL.Emit(OpCodes.Ldarg_0);
        numberGetIL.Emit(OpCodes.Ldfld, fbId);
        numberGetIL.Emit(OpCodes.Ret);

        var mbIdSetAccessor = tb.DefineMethod("set_Id", getSetAttr, null, new Type[] { typeof(int) });

        var numberSetIL = mbIdSetAccessor.GetILGenerator();
        numberSetIL.Emit(OpCodes.Ldarg_0);
        numberSetIL.Emit(OpCodes.Ldarg_1);
        numberSetIL.Emit(OpCodes.Stfld, fbId);
        numberSetIL.Emit(OpCodes.Ret);

        pbId.SetGetMethod(mbIdGetAccessor);
        pbId.SetSetMethod(mbIdSetAccessor);

        var t = tb.CreateType();
        var instance = Activator.CreateInstance(t);
        Console.WriteLine(t.GetProperty("Id").GetGetMethod().IsVirtual);
    }
}

The reason you don't find anything related to virtual in the PropertyBuilder is because properties don't have this concept. Methods can be virtual, so when you declare a virtual property you are declaring virtual getter and setter methods. Take a look at MethodAttributes enumeration.

Darin Dimitrov
ab.Save() doesn't save your created Assembly (even with the AssemblyBuilderAccess set to RunAndSave)Can you try saving and loading the assembly back into memory?I use this in my own software to work around a bug in the .NET framework that defines the assembly as a runtime assembly even after it has been saved. But if i use this on your code, it doesn't save any property or method.
Thijs Cramer
Apperently i did something wrong with your code that stopped it from working. After retrying, it works fine!
Thijs Cramer