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