コード例 #1
0
        // This must be called with _readerWriterLock held for Write
        private static Type GenerateInterfaceViewProxyType(Type viewType)
        {
            // View type is an interface let's cook an implementation
            Type        proxyType;
            TypeBuilder proxyTypeBuilder;

            Type[] interfaces       = { viewType };
            bool   requiresCritical = false;

            var proxyModuleBuilder = GetProxyModuleBuilder(requiresCritical);

            proxyTypeBuilder = proxyModuleBuilder.DefineType(
                string.Format(CultureInfo.InvariantCulture, "_proxy_{0}_{1}", viewType.FullName, Guid.NewGuid()),
                TypeAttributes.Public,
                typeof(object),
                interfaces);
            // Implement Constructor
            ConstructorBuilder proxyCtor   = proxyTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, CtorArgumentTypes);
            ILGenerator        proxyCtorIL = proxyCtor.GetILGenerator();

            proxyCtorIL.Emit(OpCodes.Ldarg_0);
            proxyCtorIL.Emit(OpCodes.Call, ObjectCtor);

            LocalBuilder exception      = proxyCtorIL.DeclareLocal(typeof(Exception));
            LocalBuilder exceptionData  = proxyCtorIL.DeclareLocal(typeof(IDictionary));
            LocalBuilder sourceType     = proxyCtorIL.DeclareLocal(typeof(Type));
            LocalBuilder value          = proxyCtorIL.DeclareLocal(typeof(object));
            LocalBuilder usesExportedMD = proxyCtorIL.DeclareLocal(typeof(bool));

            Label tryConstructView = proxyCtorIL.BeginExceptionBlock();

            // Implement interface properties
            foreach (PropertyInfo propertyInfo in viewType.GetAllProperties())
            {
                string fieldName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", propertyInfo.Name, Guid.NewGuid());

                // Cache names and type for exception
                string propertyName = propertyInfo.Name;

                Type[] propertyTypeArguments = new Type[] { propertyInfo.PropertyType };
                Type[] optionalModifiers     = null;
                Type[] requiredModifiers     = null;

                // PropertyInfo does not support GetOptionalCustomModifiers and GetRequiredCustomModifiers on Silverlight
                optionalModifiers = propertyInfo.GetOptionalCustomModifiers();
                requiredModifiers = propertyInfo.GetRequiredCustomModifiers();
                Array.Reverse(optionalModifiers);
                Array.Reverse(requiredModifiers);

                // Generate field
                FieldBuilder proxyFieldBuilder = proxyTypeBuilder.DefineField(
                    fieldName,
                    propertyInfo.PropertyType,
                    FieldAttributes.Private);

                // Generate property
                PropertyBuilder proxyPropertyBuilder = proxyTypeBuilder.DefineProperty(
                    propertyName,
                    PropertyAttributes.None,
                    propertyInfo.PropertyType,
                    propertyTypeArguments);

                // Generate constructor code for retrieving the metadata value and setting the field
                Label tryCastValue = proxyCtorIL.BeginExceptionBlock();
                Label innerTryCastValue;

                DefaultValueAttribute[] attrs = propertyInfo.GetAttributes <DefaultValueAttribute>(false);
                if (attrs.Length > 0)
                {
                    innerTryCastValue = proxyCtorIL.BeginExceptionBlock();
                }

                // In constructor set the backing field with the value from the dictionary
                Label doneGettingDefaultValue = proxyCtorIL.DefineLabel();
                GenerateLocalAssignmentFromFlag(proxyCtorIL, usesExportedMD, true);

                proxyCtorIL.Emit(OpCodes.Ldarg_1);
                proxyCtorIL.Emit(OpCodes.Ldstr, propertyInfo.Name);
                proxyCtorIL.Emit(OpCodes.Ldloca, value);
                proxyCtorIL.Emit(OpCodes.Callvirt, _mdvDictionaryTryGet);
                proxyCtorIL.Emit(OpCodes.Brtrue, doneGettingDefaultValue);

                proxyCtorIL.GenerateLocalAssignmentFromFlag(usesExportedMD, false);
                proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value);

                proxyCtorIL.MarkLabel(doneGettingDefaultValue);
                proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder);
                proxyCtorIL.Emit(OpCodes.Leave, tryCastValue);

                // catch blocks for innerTryCastValue start here
                if (attrs.Length > 0)
                {
                    proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
                    {
                        Label notUsesExportedMd = proxyCtorIL.DefineLabel();
                        proxyCtorIL.Emit(OpCodes.Ldloc, usesExportedMD);
                        proxyCtorIL.Emit(OpCodes.Brtrue, notUsesExportedMd);
                        proxyCtorIL.Emit(OpCodes.Rethrow);
                        proxyCtorIL.MarkLabel(notUsesExportedMd);
                        proxyCtorIL.GenerateLocalAssignmentFromDefaultAttribute(attrs, value);
                        proxyCtorIL.GenerateFieldAssignmentFromLocalValue(value, proxyFieldBuilder);
                    }
                    proxyCtorIL.EndExceptionBlock();
                }

                // catch blocks for tryCast start here
                proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
                {
                    proxyCtorIL.Emit(OpCodes.Stloc, exception);

                    proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
                    proxyCtorIL.Emit(OpCodes.Rethrow);
                }

                proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
                {
                    proxyCtorIL.Emit(OpCodes.Stloc, exception);

                    proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
                    proxyCtorIL.Emit(OpCodes.Rethrow);
                }

                proxyCtorIL.EndExceptionBlock();

                if (propertyInfo.CanWrite)
                {
                    // The MetadataView '{0}' is invalid because property '{1}' has a property set method.
                    throw new NotSupportedException(SR.Format(
                                                        SR.InvalidSetterOnMetadataField,
                                                        viewType,
                                                        propertyName));
                }
                if (propertyInfo.CanRead)
                {
                    // Generate "get" method implementation.
                    MethodBuilder getMethodBuilder = proxyTypeBuilder.DefineMethod(
                        "get_" + propertyName,
                        MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                        CallingConventions.HasThis,
                        propertyInfo.PropertyType,
                        requiredModifiers,
                        optionalModifiers,
                        Type.EmptyTypes, null, null);

                    proxyTypeBuilder.DefineMethodOverride(getMethodBuilder, propertyInfo.GetGetMethod());
                    ILGenerator getMethodIL = getMethodBuilder.GetILGenerator();
                    getMethodIL.Emit(OpCodes.Ldarg_0);
                    getMethodIL.Emit(OpCodes.Ldfld, proxyFieldBuilder);
                    getMethodIL.Emit(OpCodes.Ret);

                    proxyPropertyBuilder.SetGetMethod(getMethodBuilder);
                }
            }

            proxyCtorIL.Emit(OpCodes.Leave, tryConstructView);

            // catch blocks for constructView start here
            proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
            {
                proxyCtorIL.Emit(OpCodes.Stloc, exception);

                proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
                proxyCtorIL.Emit(OpCodes.Rethrow);
            }
            proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
            {
                proxyCtorIL.Emit(OpCodes.Stloc, exception);

                proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                proxyCtorIL.Emit(OpCodes.Ldloc, value);
                proxyCtorIL.Emit(OpCodes.Call, ObjectGetType);
                proxyCtorIL.Emit(OpCodes.Stloc, sourceType);
                proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
                proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemSourceType, sourceType);
                proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemValue, value);
                proxyCtorIL.Emit(OpCodes.Rethrow);
            }
            proxyCtorIL.EndExceptionBlock();

            // Finished implementing the constructor
            proxyCtorIL.Emit(OpCodes.Ret);

            // Implemet the static factory
            // public object Create(IDictionary<string, object>)
            // {
            //    return new <ProxyClass>(dictionary);
            // }
            MethodBuilder factoryMethodBuilder = proxyTypeBuilder.DefineMethod(MetadataViewGenerator.MetadataViewFactoryName, MethodAttributes.Public | MethodAttributes.Static, typeof(object), CtorArgumentTypes);
            ILGenerator   factoryIL            = factoryMethodBuilder.GetILGenerator();

            factoryIL.Emit(OpCodes.Ldarg_0);
            factoryIL.Emit(OpCodes.Newobj, proxyCtor);
            factoryIL.Emit(OpCodes.Ret);

            // Finished implementing the type
            proxyType = proxyTypeBuilder.CreateTypeInfo();

            return(proxyType);
        }
コード例 #2
0
        // This must be called with _readerWriterLock held for Write
        private static Type GenerateInterfaceViewProxyType(Type viewType)
        {
            // View type is an interface let's cook an implementation
            Type        proxyType;
            TypeBuilder proxyTypeBuilder;

            Type[] interfaces = { viewType };

            proxyTypeBuilder = ProxyModuleBuilder.DefineType(
                string.Format(CultureInfo.InvariantCulture, "_proxy_{0}_{1}", viewType.FullName, Guid.NewGuid()),
                TypeAttributes.Public,
                typeof(object),
                interfaces);

            // Implement Constructor
            ILGenerator  proxyCtorIL   = proxyTypeBuilder.CreateGeneratorForPublicConstructor(CtorArgumentTypes);
            LocalBuilder exception     = proxyCtorIL.DeclareLocal(typeof(Exception));
            LocalBuilder exceptionData = proxyCtorIL.DeclareLocal(typeof(IDictionary));
            LocalBuilder sourceType    = proxyCtorIL.DeclareLocal(typeof(Type));
            LocalBuilder value         = proxyCtorIL.DeclareLocal(typeof(object));

            Label tryConstructView = proxyCtorIL.BeginExceptionBlock();

            // Implement interface properties
            foreach (PropertyInfo propertyInfo in viewType.GetAllProperties())
            {
                string fieldName = string.Format(CultureInfo.InvariantCulture, "_{0}_{1}", propertyInfo.Name, Guid.NewGuid());

                // Cache names and type for exception
                string propertyName = string.Format(CultureInfo.InvariantCulture, "{0}", propertyInfo.Name);

                Type[] propertyTypeArguments = new Type[] { propertyInfo.PropertyType };
                Type[] optionalModifiers     = null;
                Type[] requiredModifiers     = null;

#if !SILVERLIGHT
                // PropertyInfo does not support GetOptionalCustomModifiers and GetRequiredCustomModifiers on Silverlight
                optionalModifiers = propertyInfo.GetOptionalCustomModifiers();
                requiredModifiers = propertyInfo.GetRequiredCustomModifiers();
                Array.Reverse(optionalModifiers);
                Array.Reverse(requiredModifiers);
#endif
                Type[] parameterType = (propertyInfo.CanWrite) ? propertyTypeArguments : null;

                Type[][] parameterRequiredModifiers = new Type[1][] { requiredModifiers };
                Type[][] parameterOptionalModifiers = new Type[1][] { optionalModifiers };

                // Generate field
                FieldBuilder proxyFieldBuilder = proxyTypeBuilder.DefineField(
                    fieldName,
                    propertyInfo.PropertyType,
                    FieldAttributes.Private);

                // Generate property
                PropertyBuilder proxyPropertyBuilder = proxyTypeBuilder.DefineProperty(
                    propertyName,
                    PropertyAttributes.None,
                    propertyInfo.PropertyType,
                    propertyTypeArguments);

                // Generate constructor code for retrieving the metadata value and setting the field
                Label doneGettingDefaultValue = proxyCtorIL.DefineLabel();

                // In constructor set the backing field with the value from the dictionary
                proxyCtorIL.Emit(OpCodes.Ldarg_1);
                proxyCtorIL.Emit(OpCodes.Ldstr, propertyInfo.Name);
                proxyCtorIL.Emit(OpCodes.Ldloca, value);
                proxyCtorIL.Emit(OpCodes.Callvirt, _mdvDictionaryTryGet);
                proxyCtorIL.Emit(OpCodes.Brtrue, doneGettingDefaultValue);
#if !SILVERLIGHT
                object[] attrs = propertyInfo.GetCustomAttributes(typeof(DefaultValueAttribute), false);
                if (attrs.Length > 0)
                {
                    DefaultValueAttribute defaultAttribute = (DefaultValueAttribute)attrs[0];
                    proxyCtorIL.LoadValue(defaultAttribute.Value);
                    if ((defaultAttribute.Value != null) && (defaultAttribute.Value.GetType().IsValueType))
                    {
                        proxyCtorIL.Emit(OpCodes.Box, defaultAttribute.Value.GetType());
                    }
                    proxyCtorIL.Emit(OpCodes.Stloc, value);
                }
#endif
                proxyCtorIL.MarkLabel(doneGettingDefaultValue);

                Label tryCastValue = proxyCtorIL.BeginExceptionBlock();
                proxyCtorIL.Emit(OpCodes.Ldarg_0);
                proxyCtorIL.Emit(OpCodes.Ldloc, value);

                proxyCtorIL.Emit(propertyInfo.PropertyType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, propertyInfo.PropertyType);
                proxyCtorIL.Emit(OpCodes.Stfld, proxyFieldBuilder);
                proxyCtorIL.Emit(OpCodes.Leave, tryCastValue);

                // catch blocks for tryCast start here
                proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
                {
                    proxyCtorIL.Emit(OpCodes.Stloc, exception);

                    proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
                    proxyCtorIL.Emit(OpCodes.Rethrow);
                }

                proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
                {
                    proxyCtorIL.Emit(OpCodes.Stloc, exception);

                    proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemKey, propertyName);
                    proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataItemTargetType, propertyInfo.PropertyType);
                    proxyCtorIL.Emit(OpCodes.Rethrow);
                }
                proxyCtorIL.EndExceptionBlock();


                if (propertyInfo.CanWrite)
                {
                    // The MetadataView '{0}' is invalid because property '{1}' has a property set method.
                    throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture,
                                                                  Strings.InvalidSetterOnMetadataField,
                                                                  viewType,
                                                                  propertyName));
                }
                if (propertyInfo.CanRead)
                {
                    // Generate "get" method implementation.
                    MethodBuilder getMethodBuilder = proxyTypeBuilder.DefineMethod(
                        string.Format(CultureInfo.InvariantCulture, "get_{0}", propertyName),
                        MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                        CallingConventions.HasThis,
                        propertyInfo.PropertyType,
                        requiredModifiers,
                        optionalModifiers,
                        Type.EmptyTypes, null, null);

                    proxyTypeBuilder.DefineMethodOverride(getMethodBuilder, propertyInfo.GetGetMethod());
                    ILGenerator getMethodIL = getMethodBuilder.GetILGenerator();
                    getMethodIL.Emit(OpCodes.Ldarg_0);
                    getMethodIL.Emit(OpCodes.Ldfld, proxyFieldBuilder);
                    getMethodIL.Emit(OpCodes.Ret);

                    proxyPropertyBuilder.SetGetMethod(getMethodBuilder);
                }
            }

            proxyCtorIL.Emit(OpCodes.Leave, tryConstructView);

            // catch blocks for constructView start here
            proxyCtorIL.BeginCatchBlock(typeof(NullReferenceException));
            {
                proxyCtorIL.Emit(OpCodes.Stloc, exception);

                proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
                proxyCtorIL.Emit(OpCodes.Rethrow);
            }
            proxyCtorIL.BeginCatchBlock(typeof(InvalidCastException));
            {
                proxyCtorIL.Emit(OpCodes.Stloc, exception);

                proxyCtorIL.GetExceptionDataAndStoreInLocal(exception, exceptionData);
                proxyCtorIL.Emit(OpCodes.Ldloc, value);
                proxyCtorIL.Emit(OpCodes.Call, ObjectGetType);
                proxyCtorIL.Emit(OpCodes.Stloc, sourceType);
                proxyCtorIL.AddItemToLocalDictionary(exceptionData, MetadataViewType, viewType);
                proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemSourceType, sourceType);
                proxyCtorIL.AddLocalToLocalDictionary(exceptionData, MetadataItemValue, value);
                proxyCtorIL.Emit(OpCodes.Rethrow);
            }
            proxyCtorIL.EndExceptionBlock();

            // Finished implementing interface and constructor
            proxyCtorIL.Emit(OpCodes.Ret);
            proxyType = proxyTypeBuilder.CreateType();

            return(proxyType);
        }