/// <summary>
        /// Gets the <see cref="ModuleBuilder"/> to use for generating a proxy for the given type.
        /// </summary>
        /// <param name="viewType">The type of the interface to generate a proxy for.</param>
        /// <returns>The <see cref="ModuleBuilder"/> to use.</returns>
        private static ModuleBuilder GetProxyModuleBuilder(TypeInfo viewType)
        {
            Requires.NotNull(viewType, nameof(viewType));
            Assumes.True(Monitor.IsEntered(MetadataViewFactories));

            // Dynamic assemblies are relatively expensive. We want to create as few as possible.
            // For each unique set of skip visibility check assemblies, we need a new dynamic assembly
            // because the CLR will not honor any additions to that set once the first generated type is closed.
            // So maintain a dictionary to point at dynamic modules based on the set of skip visiblity check assemblies they were generated with.
            var skipVisibilityCheckAssemblies = SkipClrVisibilityChecks.GetSkipVisibilityChecksRequirements(viewType);

            if (!TransparentProxyModuleBuilderByVisibilityCheck.TryGetValue(skipVisibilityCheckAssemblies, out ModuleBuilder moduleBuilder))
            {
                var assemblyBuilder = CreateProxyAssemblyBuilder(typeof(SecurityTransparentAttribute).GetTypeInfo().GetConstructor(Type.EmptyTypes));
                moduleBuilder = assemblyBuilder.DefineDynamicModule("MetadataViewProxiesModule");
                var skipClrVisibilityChecks = new SkipClrVisibilityChecks(assemblyBuilder, moduleBuilder);
                skipClrVisibilityChecks.SkipVisibilityChecksFor(skipVisibilityCheckAssemblies);
                TransparentProxyModuleBuilderByVisibilityCheck.Add(skipVisibilityCheckAssemblies, moduleBuilder);
            }

            return(moduleBuilder);
        }
Exemple #2
0
        private static TypeInfo GenerateInterfaceViewProxyType(Type viewType)
        {
            // View type is an interface let's cook an implementation
            TypeInfo    proxyType;
            TypeBuilder proxyTypeBuilder;

            Type[] interfaces = { viewType };

            var proxyModuleBuilder = GetProxyModuleBuilder();

            skipClrVisibilityChecks.SkipVisibilityChecksFor(viewType.GetTypeInfo());

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

            // Generate field
            const string metadataFieldName    = "metadata";
            FieldBuilder metadataFieldBuilder = proxyTypeBuilder.DefineField(
                metadataFieldName,
                CtorArgumentTypes[0],
                FieldAttributes.Private | FieldAttributes.InitOnly);
            const string metadataDefaultFieldName    = "metadataDefault";
            FieldBuilder metadataDefaultFieldBuilder = proxyTypeBuilder.DefineField(
                metadataDefaultFieldName,
                CtorArgumentTypes[1],
                FieldAttributes.Private | FieldAttributes.InitOnly);

            // Implement Constructor
            ConstructorBuilder proxyCtor   = proxyTypeBuilder.DefineConstructor(MethodAttributes.Private, CallingConventions.Standard, CtorArgumentTypes);
            ILGenerator        proxyCtorIL = proxyCtor.GetILGenerator();

            // : base()
            proxyCtorIL.Emit(OpCodes.Ldarg_0);
            proxyCtorIL.Emit(OpCodes.Call, ObjectCtor);

            // this.metadata = metadata;
            proxyCtorIL.Emit(OpCodes.Ldarg_0);
            proxyCtorIL.Emit(OpCodes.Ldarg_1);
            proxyCtorIL.Emit(OpCodes.Stfld, metadataFieldBuilder);

            // this.metadataDefault = metadataDefault;
            proxyCtorIL.Emit(OpCodes.Ldarg_0);
            proxyCtorIL.Emit(OpCodes.Ldarg_2);
            proxyCtorIL.Emit(OpCodes.Stfld, metadataDefaultFieldBuilder);

            proxyCtorIL.Emit(OpCodes.Ret);

            foreach (PropertyInfo propertyInfo in viewType.GetAllProperties())
            {
                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 property
                PropertyBuilder proxyPropertyBuilder = proxyTypeBuilder.DefineProperty(
                    propertyName,
                    PropertyAttributes.None,
                    propertyInfo.PropertyType,
                    propertyTypeArguments);

                // 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();

                // object value;
                LocalBuilder valueLocal = getMethodIL.DeclareLocal(typeof(object));

                // this.metadata.TryGetValue(propertyName, out value);
                getMethodIL.Emit(OpCodes.Ldarg_0);
                getMethodIL.Emit(OpCodes.Ldfld, metadataFieldBuilder);
                getMethodIL.Emit(OpCodes.Ldstr, propertyName);
                getMethodIL.Emit(OpCodes.Ldloca_S, valueLocal);
                getMethodIL.Emit(OpCodes.Callvirt, MdvDictionaryTryGet);

                // If that succeeded, prepare to return.
                Label returnLabel = getMethodIL.DefineLabel();
                getMethodIL.Emit(OpCodes.Brtrue_S, returnLabel);

                // Otherwise get the value from the default metadata dictionary.
                getMethodIL.Emit(OpCodes.Ldarg_0);
                getMethodIL.Emit(OpCodes.Ldfld, metadataDefaultFieldBuilder);
                getMethodIL.Emit(OpCodes.Ldstr, propertyName);
                getMethodIL.Emit(OpCodes.Callvirt, MdvDictionaryIndexer);
                getMethodIL.Emit(OpCodes.Stloc_0);

                getMethodIL.MarkLabel(returnLabel);
                getMethodIL.Emit(OpCodes.Ldloc_0);
                getMethodIL.Emit(propertyInfo.PropertyType.GetTypeInfo().IsValueType ? OpCodes.Unbox_Any : OpCodes.Isinst, propertyInfo.PropertyType);
                getMethodIL.Emit(OpCodes.Ret);

                proxyPropertyBuilder.SetGetMethod(getMethodBuilder);
            }

            // Implement the static factory
            //// public static object Create(IReadOnlyDictionary<string, object>, IReadOnlyDictionary<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.Ldarg_1);
            factoryIL.Emit(OpCodes.Newobj, proxyCtor);
            factoryIL.Emit(OpCodes.Ret);

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

            return(proxyType);
        }