private static TypeInfo GenerateInterfaceViewProxyType()

in src/Microsoft.VisualStudio.Composition/Configuration/MetadataViewGenerator.cs [153:280]


        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(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!;
        }