jeudi 14 avril 2016

Reflection Emit for Proxies

I need to do this question since, I can't proceed with code. I am doing one personal implementation of a ORM, and I avoid to use reflection to create objects whenever possible. Now, regarding to ORM contextualized, normally we get objects from there and we "Track them" through their properties.

Everytime I return object from my ORM I return Proxies, where they extend from the original object and Internally they have 1 field, that points to the ORM for changing tracking purposes.

My question is very simple, I need to create one method that returns the Proxy type that when users interact through object properties, those will behind the scenes talk with the ORM.

I am using Reflection.Emit to this task, and I have I good IL behind the scenes, but seems that the code is not called.

Can you provide me light to solve this? or some technique that I can walk through and see by myself what is wrong?

    internal static Type EmitProxy(Type type)
    {
        TypeBuilder proxy = s_moduleBuilder.DefineType(type.Name + "Impl", TypeAttributes.Public, type);

        // define OMapper and IsProxy properties in each instance
        PropertyBuilder propProxy = proxy.AddProperty(PROXY_PROPERTY_NAME, typeof(bool));
        PropertyBuilder propOMapperInstance = proxy.AddProperty(OMapper_PROPERTY_NAME, typeof(OMapper));


        MethodBuilder methodNotifyPropertyChangeBuilder = proxy.AddMethod("NotifyPropertyChange", MethodAttributes.Public, typeof(void), new[] { typeof(string) }, il =>
        {
            // private void NotifyPropertyChange(string propertyName) {
            //      this.OMapperProperty.PutObjectForUpdate(proxy, propertyName);
            // }
            il.Emit(op.Ldarg_0);    // push this.
            il.Emit(op.Call, propOMapperInstance.GetGetMethod());
            // il.Emit(op.Ldarg_0);    // push this.
            il.Emit(op.Ldstr, "id");    // push propertyName.
            il.Emit(op.Call, typeof(OMapperContextExecuter).GetMethod("PutObjectForUpdate", BindingFlags.Public | BindingFlags.Instance));
        });



        // override base properties
        foreach (var pi in type.GetProperties(OMapper.s_PropertiesFlags))
        {
            // save base setMethod - same logic
            MethodInfo SetMethodHook = pi.GetSetMethod();
            MethodBuilder overrideSetBuilder = proxy.AddMethod("set_" + pi.Name, SetMethodHook.Attributes, SetMethodHook.ReturnType, new[] { pi.PropertyType }, il =>
            {
                // maintain the old behavior
                il.Emit(op.Ldarg_0);        // push this
                il.Emit(op.Ldarg_1);        // push value
                il.Emit(op.Call, SetMethodHook);

                il.Emit(op.Ldarg_0);        // push this.
                il.Emit(op.Ldstr, pi.Name); // push propertyName
                il.Emit(op.Call, methodNotifyPropertyChangeBuilder);        // push value

            });
        }


        var t =  proxy.CreateType();

        s_assemblyBuilder.Save(s_assemblyName.Name);

        return t;

        // 
    }

Those methods through lambda are just there to refactoring purposes; Inside AddProperty, I define Get/Set methods and create the property.





Aucun commentaire:

Enregistrer un commentaire