예제 #1
0
        protected Type CreateProxyType(Type type)
        {
            if (type.GetConstructor(new Type[0]) == null)
            {
                throw new PatchProxyTypeException($"Type {type} doesn't have an empty constructor.");
            }

            RuntimeTypeBuilder proxyBuilder = new RuntimeTypeBuilder($"{{Guid.NewGuid()}}.{type.FullName}Patch", type);

            FieldBuilder modified      = proxyBuilder.DefineField("_modified", typeof(HashSet <string>), FieldAttributes.Private);
            var          modifiedField = Field(proxyBuilder.This, modified);

            foreach (PropertyInfo propInfo in type.GetRuntimeProperties())
            {
                if (propInfo.CanRead && propInfo.CanWrite && propInfo.GetSetMethod().IsVirtual)
                {
                    ParameterExpression valueExpr = Parameter(propInfo.PropertyType, "value");

                    var baseGet = Call(proxyBuilder.Base, propInfo.GetGetMethod());

                    proxyBuilder.OverrideMethod(propInfo.GetSetMethod(),
                                                new[] { valueExpr },
                                                If(NotEqual(baseGet, valueExpr),
                                                   Then(
                                                       If(IsNull(modifiedField),
                                                          Assign(modifiedField, New(typeof(HashSet <string>)))
                                                          ),
                                                       Call("Add", modifiedField, Constant(propInfo.Name)),
                                                       Call(proxyBuilder.Base, propInfo.SetMethod, valueExpr)
                                                       )
                                                   )
                                                );
                }
            }

            proxyBuilder.DefineMethod("Reset", null,
                                      Block(
                                          If(IsNotNull(modifiedField),
                                             Call("Clear", modifiedField)
                                             )
                                          )
                                      );

            var propNameParam = Parameter(typeof(string), "propName");

            proxyBuilder.DefineMethod("IsSet",
                                      new[] { propNameParam },
                                      Block(
                                          Variable("result", Constant(false), out Expression result),
                                          If(IsNotNull(modifiedField),
                                             Assign(result, Call("Contains", modifiedField, propNameParam))
                                             ),
                                          Result(result)
                                          )
                                      );

            proxyBuilder.AutoImplementInterface(typeof(IPatch));

            return(proxyBuilder.Create());
        }
예제 #2
0
        public void access_local_field()
        {
            RuntimeTypeBuilder  typeBuilder = new RuntimeTypeBuilder("AccessLocalField");
            ParameterExpression a           = Parameter(typeof(int), "a");
            ParameterExpression b           = Parameter(typeof(int), "b");

            var field = typeBuilder.DefineField("TestField", typeof(string));

            typeBuilder.DefineMethod("TestMethod",
                                     null,
                                     Field(typeBuilder.This, field)
                                     );

            Type   newType     = typeBuilder.Create();
            object newInstance = Activator.CreateInstance(newType);

            FieldInfo fieldInfo = newType.GetField("TestField");

            fieldInfo.SetValue(newInstance, "testValue");
            MethodInfo testMethodInfo = newType.GetMethod("TestMethod");
            object     result         = testMethodInfo.Invoke(newInstance, null);

            Assert.Equal("testValue", result);
        }