vendredi 30 décembre 2016

Reflection Emit for Property Getter

I want to build type dynamically like this:

public class Sample
{
    Sample Parent { get; set; }
    public Sample(Sample parent)
    {
        Parent = parent;
    }

    public int Depth
    {
        get
        {
            if (Parent == null)
                return -1;
            else
                return Parent.Depth + 1;
        }
    }
}

The code I write is :

        const string assemblyName = "SampleAssembly";
        const string parentPproperty = "Parent";
        const string depthProperty = "Depth";
        const string typeName = "Sample";     
        const string assemblyFileName = assemblyName + ".dll";

        AppDomain domain = AppDomain.CurrentDomain;
        AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName);
        TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
        FieldBuilder parentField = typeBuilder.DefineField($"_{parentPproperty}", typeBuilder, FieldAttributes.Private);
        PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(parentPproperty, PropertyAttributes.None, parentField.FieldType, Type.EmptyTypes);
        MethodBuilder getParentMethod = typeBuilder.DefineMethod($"get_{propertyBuilder.Name}", DynamicMethodBuilder.GetMethodAttrs, parentField.FieldType, Type.EmptyTypes);
        ILGenerator il = getParentMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, parentField);
        il.Emit(OpCodes.Ret);
        propertyBuilder.SetGetMethod(getParentMethod);

        MethodBuilder setParentMethod = typeBuilder.DefineMethod($"set_{propertyBuilder.Name}", DynamicMethodBuilder.GetMethodAttrs, null, Type.EmptyTypes);
        il = setParentMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stfld, parentField);
        il.Emit(OpCodes.Ret);
        propertyBuilder.SetSetMethod(setParentMethod);


        parentField = typeBuilder.DefineField($"_{depthProperty}", typeBuilder, FieldAttributes.Private);
        propertyBuilder = typeBuilder.DefineProperty(depthProperty, PropertyAttributes.None, parentField.FieldType, Type.EmptyTypes);
        MethodBuilder getDepthMethod = typeBuilder.DefineMethod($"get_{depthProperty}", DynamicMethodBuilder.GetMethodAttrs, parentField.FieldType, Type.EmptyTypes);
        il = getDepthMethod.GetILGenerator();
        LocalBuilder lb = il.DeclareLocal(typeof(bool));

        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, getParentMethod);
        il.Emit(OpCodes.Ldnull);
        il.Emit(OpCodes.Ceq);
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Brfalse_S);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Stloc_1);
        il.Emit(OpCodes.Br_S);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, getParentMethod);
        il.Emit(OpCodes.Callvirt, getDepthMethod);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Add);
        il.Emit(OpCodes.Stloc_1);
        il.Emit(OpCodes.Br_S);
        il.Emit(OpCodes.Ldloc_1);
        il.Emit(OpCodes.Ret);
        propertyBuilder.SetGetMethod(getDepthMethod);

        ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeBuilder });
        il= constructor.GetILGenerator();            
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Call, setParentMethod);          
        il.Emit(OpCodes.Ret);

        Type type = typeBuilder.CreateType();
        var obj1 = Activator.CreateInstance(type, null);

        var obj2 = Activator.CreateInstance(type, obj1);

        assemblyBuilder.Save(assemblyFileName);

I think I had problem in building constructor and Depth property getter method.

Please help me get out of this.

Instance is not created as well.

Thanks





Aucun commentaire:

Enregistrer un commentaire