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