// Emit a surrogate property for a CLR property.
        // The surrogate code we'll generate will look like this:
        // public <PropertyType> <PropertyName> {
        //     get {
        //         // For normal types.
        //         return _$wrapper.<PropertyName>;
        //
        //         // For Binary.
        //         Binary value = _$wrapper.<PropertyName>;
        //         if (value == null) {
        //             return null;
        //         }
        //         return value.ToArray();
        //     }
        //     set {
        //         if (value == null) {
        //             return;
        //         }
        //
        //         // For normal types.
        //         _$wrapper.<PropertyName> = value;
        //
        //         // For Binary.
        //         Binary valueToStore;
        //         if (value == null) {
        //             valueToStore = null;
        //         }
        //         else {
        //             valueToStore = new Binary(value);
        //         }
        //         _$wrapper.<PropertyName> = valueToStore;
        //     }
        // }
        private static void EmitClrProperty(TypeBuilder typeBuilder, FieldInfo wrapperField, PropertyDescriptor pd, PropertyInfo pi, string name)
        {
            Type            propertyType    = SerializationUtility.GetClientType(pi.PropertyType);
            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.None, propertyType, null);

            CustomAttributeBuilder dataMemberAtt = DataContractSurrogateGenerator.GetDataMemberAttributeBuilder(
                pd.Attributes.OfType <DataMemberAttribute>().FirstOrDefault());

            propertyBuilder.SetCustomAttribute(dataMemberAtt);

            // get {
            //     return ((Entity)$wrapper).Property;
            // }
            MethodBuilder getPropertyMethodBuilder = typeBuilder.DefineMethod("get_" + name, MethodAttributes.Public, propertyType, Type.EmptyTypes);
            ILGenerator   generator = getPropertyMethodBuilder.GetILGenerator();

            // Push the wrapper object onto the stack.
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, wrapperField);
            generator.Emit(OpCodes.Castclass, pi.DeclaringType);

            // Call the property getter.
            generator.Emit(OpCodes.Callvirt, pi.GetGetMethod());

            // Deal with client-server type conversions.
            if (propertyType != pi.PropertyType)
            {
                EmitToClientConversion(generator, pi.PropertyType, propertyType);
            }

            generator.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropertyMethodBuilder);

            MethodBuilder setPropertyMethodBuilder = typeBuilder.DefineMethod("set_" + name, MethodAttributes.Public, null, new Type[] { propertyType });

            generator = setPropertyMethodBuilder.GetILGenerator();

            Label returnLabel = generator.DefineLabel();

            // Data members require a getter and setter. However, if the real property is read-only, make sure
            // our surrogate property setter is a no-op.
            MethodInfo setMethod = pi.GetSetMethod();

            if (setMethod != null && setMethod.IsPublic)
            {
                // NOTE: We don't ever set null values, because a property may be required. For
                //       original objects however it's possible that required properties are not
                //       roundtripped, as they may not have RoundtripOriginalAttribute.
                // set {
                //     if (value != null) {
                //         _$wrapper.Property = value;
                //     }
                // }

                // If the value is null, return.
                if (!propertyType.IsValueType)
                {
                    generator.Emit(OpCodes.Ldarg_1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }
                else if (TypeUtility.IsNullableType(propertyType))
                {
                    generator.Emit(OpCodes.Ldarga_S, 1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }

                // Push the wrapper object onto the stack.
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, wrapperField);
                generator.Emit(OpCodes.Castclass, pi.DeclaringType);

                // Push the value onto the stack.
                generator.Emit(OpCodes.Ldarg_1);

                // Deal with client-server type conversions.
                if (propertyType != pi.PropertyType)
                {
                    EmitToServerConversion(generator, propertyType, pi.PropertyType);
                }

                // Call the property setter.
                generator.Emit(OpCodes.Callvirt, setMethod);
            }

            generator.MarkLabel(returnLabel);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setPropertyMethodBuilder);
        }
        // Emit a surrogate property for a virtual property (a property that doesn't exist on the physical CLR type).
        // The PropertyDescriptor for each virtual property is initialized in the type initializer of a surrogate type.
        // The surrogate code we'll generate will look like this:
        // public <PropertyType> <PropertyName> {
        //     get {
        //         // For reference types.
        //         return (<PropertyType>)$<PropertyName>.GetValue(_$wrapper);
        //
        //         // For value types.
        //         object value = $<PropertyName>.GetValue(_$wrapper);
        //         if (value == null) {
        //             return default(value);
        //         }
        //         return (<PropertyType>)value;
        //
        //         // For Binary.
        //         Binary value = (Binary)$<PropertyName>.GetValue(_$wrapper);
        //         if (value == null) {
        //             return null;
        //         }
        //         return value.ToArray();
        //     }
        //     set {
        //         if (value == null) {
        //             return;
        //         }
        //
        //         // For normal types.
        //         $<PropertyName>.SetValue(_$wrapper, value);
        //
        //         // For value types.
        //         $<PropertyName>.SetValue(_$wrapper, (object)value);
        //
        //         // For Binary.
        //         Binary valueToStore;
        //         if (value == null) {
        //             valueToStore = null;
        //         }
        //         else {
        //             valueToStore = new Binary(value);
        //         }
        //         $<PropertyName>.SetValue(_$wrapper, valueToStore);
        //     }
        // }
        private static void EmitAttachedProperty(TypeBuilder typeBuilder, FieldInfo wrapperField, Lazy <ILGenerator> typeInitializerFactory, PropertyDescriptor pd, string name)
        {
            // private static PropertyDescriptor $property;
            FieldBuilder propertyDescFieldBuilder = typeBuilder.DefineField("$" + name, typeof(PropertyDescriptor), FieldAttributes.Private | FieldAttributes.Static);

            EmitPropertyInitializer(propertyDescFieldBuilder, typeInitializerFactory, name);

            Type            propertyType    = SerializationUtility.GetClientType(pd.PropertyType);
            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.None, propertyType, null);

            CustomAttributeBuilder dataMemberAtt = DataContractSurrogateGenerator.GetDataMemberAttributeBuilder(
                pd.Attributes[typeof(DataMemberAttribute)] as DataMemberAttribute);

            propertyBuilder.SetCustomAttribute(dataMemberAtt);

            // get {
            //     return $property.GetValue(_$wrapper);
            // }
            MethodBuilder getPropertyMethodBuilder = typeBuilder.DefineMethod("get_" + name, MethodAttributes.Public, propertyType, Type.EmptyTypes);
            ILGenerator   generator = getPropertyMethodBuilder.GetILGenerator();

            // Get the PropertyDescriptor.
            generator.Emit(OpCodes.Ldsfld, propertyDescFieldBuilder);

            // Push the wrapper object onto the stack. We'll use it as an argument for our
            // call to GetValue later on.
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, wrapperField);

            // PropertyDescriptor.GetValue(_$wrapper).
            generator.Emit(OpCodes.Callvirt, typeof(PropertyDescriptor).GetMethod("GetValue"));

            // Unbox/cast.
            DynamicMethodUtility.EmitFromObjectConversion(generator, pd.PropertyType);

            // Deal with client-server type conversions.
            if (propertyType != pd.PropertyType)
            {
                EmitToClientConversion(generator, pd.PropertyType, propertyType);
            }

            generator.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropertyMethodBuilder);

            MethodBuilder setPropertyMethodBuilder = typeBuilder.DefineMethod("set_" + name, MethodAttributes.Public, null, new Type[] { propertyType });

            generator = setPropertyMethodBuilder.GetILGenerator();

            Label returnLabel = generator.DefineLabel();

            // Data members require a getter and setter. However, if the real property is read-only, make sure
            // our surrogate property setter is a no-op.
            if (!pd.IsReadOnly)
            {
                // NOTE: We don't ever set null values, because a property may be required. For
                //       original objects however it's possible that required properties are not
                //       roundtripped, as they may not have RoundtripOriginalAttribute.
                // set {
                //     if (value != null) {
                //         $property.SetValue(_$wrapper, value);
                //     }
                // }

                // If the value is null, return.
                if (!propertyType.IsValueType)
                {
                    generator.Emit(OpCodes.Ldarg_1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }
                else if (TypeUtility.IsNullableType(propertyType))
                {
                    generator.Emit(OpCodes.Ldarga_S, 1);
                    EmitBranchIfNull(generator, propertyType, returnLabel);
                }

                // Get the PropertyDescriptor.
                generator.Emit(OpCodes.Ldsfld, propertyDescFieldBuilder);

                // Push the wrapper object onto the stack. We'll use it as an argument for our
                // call to SetValue later on.
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, wrapperField);

                // Push the value onto the stack. We'll use it as the 2nd argument for
                // our call to SetValue.
                generator.Emit(OpCodes.Ldarg_1);

                // Deal with client-server type conversions.
                if (propertyType != pd.PropertyType)
                {
                    EmitToServerConversion(generator, propertyType, pd.PropertyType);
                }

                // Box value types.
                DynamicMethodUtility.EmitToObjectConversion(generator, pd.PropertyType);

                // PropertyDescriptor.SetValue(_$wrapper, value).
                generator.Emit(OpCodes.Callvirt, typeof(PropertyDescriptor).GetMethod("SetValue"));
            }

            generator.MarkLabel(returnLabel);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setPropertyMethodBuilder);
        }