Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / clr / src / BCL / System / Reflection / Emit / CustomAttributeBuilder.cs / 1 / CustomAttributeBuilder.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: CustomAttrbuteBuilder ** ** ** CustomAttributeBuilder is a helper class to help building custom attribute. ** ** ===========================================================*/ namespace System.Reflection.Emit { using System; using System.Reflection; using System.Reflection.Emit; using System.IO; using System.Text; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Globalization; [HostProtection(MayLeakOnAbort = true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(_CustomAttributeBuilder))] [System.Runtime.InteropServices.ComVisible(true)] public class CustomAttributeBuilder : _CustomAttributeBuilder { // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs) { InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[]{}, new Object[]{}, new FieldInfo[]{}, new Object[]{}); } // public constructor to form the custom attribute with constructor, constructor // parameters and named properties. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues) { InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, new FieldInfo[]{}, new Object[]{}); } // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, FieldInfo[] namedFields, Object[] fieldValues) { InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[]{}, new Object[]{}, namedFields, fieldValues); } // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues) { InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues); } private const byte SERIALIZATION_TYPE_BOOLEAN = SignatureHelper.ELEMENT_TYPE_BOOLEAN; private const byte SERIALIZATION_TYPE_CHAR = SignatureHelper.ELEMENT_TYPE_CHAR; private const byte SERIALIZATION_TYPE_I1 = SignatureHelper.ELEMENT_TYPE_I1; private const byte SERIALIZATION_TYPE_U1 = SignatureHelper.ELEMENT_TYPE_U1; private const byte SERIALIZATION_TYPE_I2 = SignatureHelper.ELEMENT_TYPE_I2; private const byte SERIALIZATION_TYPE_U2 = SignatureHelper.ELEMENT_TYPE_U2; private const byte SERIALIZATION_TYPE_I4 = SignatureHelper.ELEMENT_TYPE_I4; private const byte SERIALIZATION_TYPE_U4 = SignatureHelper.ELEMENT_TYPE_U4; private const byte SERIALIZATION_TYPE_I8 = SignatureHelper.ELEMENT_TYPE_I8; private const byte SERIALIZATION_TYPE_U8 = SignatureHelper.ELEMENT_TYPE_U8; private const byte SERIALIZATION_TYPE_R4 = SignatureHelper.ELEMENT_TYPE_R4; private const byte SERIALIZATION_TYPE_R8 = SignatureHelper.ELEMENT_TYPE_R8; private const byte SERIALIZATION_TYPE_STRING = SignatureHelper.ELEMENT_TYPE_STRING; private const byte SERIALIZATION_TYPE_SZARRAY = SignatureHelper.ELEMENT_TYPE_SZARRAY; private const byte SERIALIZATION_TYPE_TYPE = 0x50; private const byte SERIALIZATION_TYPE_TAGGED_OBJECT = 0x51; private const byte SERIALIZATION_TYPE_FIELD = 0x53; private const byte SERIALIZATION_TYPE_PROPERTY = 0x54; private const byte SERIALIZATION_TYPE_ENUM = 0x55; // Check that a type is suitable for use in a custom attribute. private bool ValidateType(Type t) { if (t.IsPrimitive || t == typeof(String) || t == typeof(Type)) return true; if (t.IsEnum) { switch (Type.GetTypeCode(Enum.GetUnderlyingType(t))) { case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: return true; default: return false; } } if (t.IsArray) { if (t.GetArrayRank() != 1) return false; return ValidateType(t.GetElementType()); } return t == typeof(Object); } internal void InitCustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues) { if (con == null) throw new ArgumentNullException("con"); if (constructorArgs == null) throw new ArgumentNullException("constructorArgs"); if (namedProperties == null) throw new ArgumentNullException("constructorArgs"); if (propertyValues == null) throw new ArgumentNullException("propertyValues"); if (namedFields == null) throw new ArgumentNullException("namedFields"); if (fieldValues == null) throw new ArgumentNullException("fieldValues"); if (namedProperties.Length != propertyValues.Length) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedProperties, propertyValues"); if (namedFields.Length != fieldValues.Length) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedFields, fieldValues"); if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static || (con.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructor")); if ((con.CallingConvention & CallingConventions.Standard) != CallingConventions.Standard) throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructorCallConv")); // Cache information used elsewhere. m_con = con; m_constructorArgs = new Object[constructorArgs.Length]; Array.Copy(constructorArgs, m_constructorArgs, constructorArgs.Length); Type[] paramTypes; int i; // Get the types of the constructor's formal parameters. if (con is ConstructorBuilder) { paramTypes = ((ConstructorBuilder)con).GetParameterTypes(); } else { ParameterInfo[] paramInfos = con.GetParametersNoCopy(); paramTypes = new Type[paramInfos.Length]; for (i = 0; i < paramInfos.Length; i++) paramTypes[i] = paramInfos[i].ParameterType; } // Since we're guaranteed a non-var calling convention, the number of arguments must equal the number of parameters. if (paramTypes.Length != constructorArgs.Length) throw new ArgumentException(Environment.GetResourceString("Argument_BadParameterCountsForConstructor")); // Verify that the constructor has a valid signature (custom attributes only support a subset of our type system). for (i = 0; i < paramTypes.Length; i++) if (!ValidateType(paramTypes[i])) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Now verify that the types of the actual parameters are compatible with the types of the formal parameters. for (i = 0; i < paramTypes.Length; i++) { if (constructorArgs[i] == null) continue; TypeCode paramTC = Type.GetTypeCode(paramTypes[i]); if (paramTC != Type.GetTypeCode(constructorArgs[i].GetType())) if (paramTC != TypeCode.Object || !ValidateType(constructorArgs[i].GetType())) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForConstructor"), i)); } // Allocate a memory stream to represent the CA blob in the metadata and a binary writer to help format it. MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); // Write the blob protocol version (currently 1). writer.Write((ushort)1); // Now emit the constructor argument values (no need for types, they're inferred from the constructor signature). for (i = 0; i < constructorArgs.Length; i++) EmitValue(writer, paramTypes[i], constructorArgs[i]); // Next a short with the count of properties and fields. writer.Write((ushort)(namedProperties.Length + namedFields.Length)); // Emit all the property sets. for (i = 0; i < namedProperties.Length; i++) { // Validate the property. if (namedProperties[i] == null) throw new ArgumentNullException("namedProperties[" + i + "]"); // Allow null for non-primitive types only. Type propType = namedProperties[i].PropertyType; if (propertyValues[i] == null && propType.IsPrimitive) throw new ArgumentNullException("propertyValues[" + i + "]"); // Validate property type. if (!ValidateType(propType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Property has to be writable. if (!namedProperties[i].CanWrite) throw new ArgumentException(Environment.GetResourceString("Argument_NotAWritableProperty")); // Property has to be from the same class or base class as ConstructorInfo. if (namedProperties[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedProperties[i].DeclaringType)) { // Might have failed check because one type is a XXXBuilder // and the other is not. Deal with these special cases // separately. if (!TypeBuilder.IsTypeEqual(namedProperties[i].DeclaringType, con.DeclaringType)) { // IsSubclassOf is overloaded to do the right thing if // the constructor is a TypeBuilder, but we still need // to deal with the case where the property's declaring // type is one. if (!(namedProperties[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedProperties[i].DeclaringType).m_runtimeType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadPropertyForConstructorBuilder")); } } // Make sure the property's type can take the given value. // Note that there will be no coersion. if (propertyValues[i] != null && propType != typeof(Object) && Type.GetTypeCode(propertyValues[i].GetType()) != Type.GetTypeCode(propType)) throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch")); // First a byte indicating that this is a property. writer.Write(SERIALIZATION_TYPE_PROPERTY); // Emit the property type, name and value. EmitType(writer, propType); EmitString(writer, namedProperties[i].Name); EmitValue(writer, propType, propertyValues[i]); } // Emit all the field sets. for (i = 0; i < namedFields.Length; i++) { // Validate the field. if (namedFields[i] == null) throw new ArgumentNullException("namedFields[" + i + "]"); // Allow null for non-primitive types only. Type fldType = namedFields[i].FieldType; if (fieldValues[i] == null && fldType.IsPrimitive) throw new ArgumentNullException("fieldValues[" + i + "]"); // Validate field type. if (!ValidateType(fldType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Field has to be from the same class or base class as ConstructorInfo. if (namedFields[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedFields[i].DeclaringType)) { // Might have failed check because one type is a XXXBuilder // and the other is not. Deal with these special cases // separately. if (!TypeBuilder.IsTypeEqual(namedFields[i].DeclaringType, con.DeclaringType)) { // IsSubclassOf is overloaded to do the right thing if // the constructor is a TypeBuilder, but we still need // to deal with the case where the field's declaring // type is one. if (!(namedFields[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedFields[i].DeclaringType).m_runtimeType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadFieldForConstructorBuilder")); } } // Make sure the field's type can take the given value. // Note that there will be no coersion. if (fieldValues[i] != null && fldType != typeof(Object) && Type.GetTypeCode(fieldValues[i].GetType()) != Type.GetTypeCode(fldType)) throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch")); // First a byte indicating that this is a field. writer.Write(SERIALIZATION_TYPE_FIELD); // Emit the field type, name and value. EmitType(writer, fldType); EmitString(writer, namedFields[i].Name); EmitValue(writer, fldType, fieldValues[i]); } // Create the blob array. m_blob = ((MemoryStream)writer.BaseStream).ToArray(); } private void EmitType(BinaryWriter writer, Type type) { if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.SByte: writer.Write(SERIALIZATION_TYPE_I1); break; case TypeCode.Byte: writer.Write(SERIALIZATION_TYPE_U1); break; case TypeCode.Char: writer.Write(SERIALIZATION_TYPE_CHAR); break; case TypeCode.Boolean: writer.Write(SERIALIZATION_TYPE_BOOLEAN); break; case TypeCode.Int16: writer.Write(SERIALIZATION_TYPE_I2); break; case TypeCode.UInt16: writer.Write(SERIALIZATION_TYPE_U2); break; case TypeCode.Int32: writer.Write(SERIALIZATION_TYPE_I4); break; case TypeCode.UInt32: writer.Write(SERIALIZATION_TYPE_U4); break; case TypeCode.Int64: writer.Write(SERIALIZATION_TYPE_I8); break; case TypeCode.UInt64: writer.Write(SERIALIZATION_TYPE_U8); break; case TypeCode.Single: writer.Write(SERIALIZATION_TYPE_R4); break; case TypeCode.Double: writer.Write(SERIALIZATION_TYPE_R8); break; default: BCLDebug.Assert(false, "Invalid primitive type"); break; } } else if (type.IsEnum) { writer.Write(SERIALIZATION_TYPE_ENUM); EmitString(writer, type.AssemblyQualifiedName); } else if (type == typeof(String)) { writer.Write(SERIALIZATION_TYPE_STRING); } else if (type == typeof(Type)) { writer.Write(SERIALIZATION_TYPE_TYPE); } else if (type.IsArray) { writer.Write(SERIALIZATION_TYPE_SZARRAY); EmitType(writer, type.GetElementType()); } else { // Tagged object case. writer.Write(SERIALIZATION_TYPE_TAGGED_OBJECT); } } private void EmitString(BinaryWriter writer, String str) { // Strings are emitted with a length prefix in a compressed format (1, 2 or 4 bytes) as used internally by metadata. byte[] utf8Str = Encoding.UTF8.GetBytes(str); uint length = (uint)utf8Str.Length; if (length <= 0x7f) { writer.Write((byte)length); } else if (length <= 0x3fff) { writer.Write((byte)((length >> 8) | 0x80)); writer.Write((byte)(length & 0xff)); } else { writer.Write((byte)((length >> 24) | 0xc0)); writer.Write((byte)((length >> 16) & 0xff)); writer.Write((byte)((length >> 8) & 0xff)); writer.Write((byte)(length & 0xff)); } writer.Write(utf8Str); } private void EmitValue(BinaryWriter writer, Type type, Object value) { if (type.IsEnum) { switch (Type.GetTypeCode(Enum.GetUnderlyingType(type))) { case TypeCode.SByte: writer.Write((sbyte)value); break; case TypeCode.Byte: writer.Write((byte)value); break; case TypeCode.Int16: writer.Write((short)value); break; case TypeCode.UInt16: writer.Write((ushort)value); break; case TypeCode.Int32: writer.Write((int)value); break; case TypeCode.UInt32: writer.Write((uint)value); break; case TypeCode.Int64: writer.Write((long)value); break; case TypeCode.UInt64: writer.Write((ulong)value); break; default: BCLDebug.Assert(false, "Invalid enum base type"); break; } } else if (type == typeof(String)) { if (value == null) writer.Write((byte)0xff); else EmitString(writer, (String)value); } else if (type == typeof(Type)) { if (value == null) writer.Write((byte)0xff); else { String typeName = TypeNameBuilder.ToString((Type)value, TypeNameBuilder.Format.AssemblyQualifiedName); if (typeName == null) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidTypeForCA"), value.GetType())); EmitString(writer, typeName); } } else if (type.IsArray) { if (value == null) writer.Write((uint)0xffffffff); else { Array a = (Array)value; Type et = type.GetElementType(); writer.Write(a.Length); for (int i = 0; i < a.Length; i++) EmitValue(writer, et, a.GetValue(i)); } } else if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.SByte: writer.Write((sbyte)value); break; case TypeCode.Byte: writer.Write((byte)value); break; case TypeCode.Char: writer.Write(Convert.ToInt16((char)value)); break; case TypeCode.Boolean: writer.Write((byte)((bool)value ? 1 : 0)); break; case TypeCode.Int16: writer.Write((short)value); break; case TypeCode.UInt16: writer.Write((ushort)value); break; case TypeCode.Int32: writer.Write((int)value); break; case TypeCode.UInt32: writer.Write((uint)value); break; case TypeCode.Int64: writer.Write((long)value); break; case TypeCode.UInt64: writer.Write((ulong)value); break; case TypeCode.Single: writer.Write((float)value); break; case TypeCode.Double: writer.Write((double)value); break; default: BCLDebug.Assert(false, "Invalid primitive type"); break; } } else if (type == typeof(object)) { // Tagged object case. Type instances aren't actually Type, they're some subclass (such as RuntimeType or // TypeBuilder), so we need to canonicalize this case back to Type. If we have a null value we follow the convention // used by C# and emit a null typed as a string (it doesn't really matter what type we pick as long as it's a // reference type). Type ot = value == null ? typeof(String) : value is Type ? typeof(Type) : value.GetType(); EmitType(writer, ot); EmitValue(writer, ot, value); } else { string typename = "null"; if (value != null) typename = value.GetType().ToString(); throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForCAB"), typename)); } } // return the byte interpretation of the custom attribute internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner) { CreateCustomAttribute(mod, tkOwner, mod.GetConstructorToken(m_con).Token, false); } //************************************************* // Upon saving to disk, we need to create the memberRef token for the custom attribute's type // first of all. So when we snap the in-memory module for on disk, this token will be there. // We also need to enforce the use of MemberRef. Because MemberDef token might move. // This function has to be called before we snap the in-memory module for on disk (i.e. Presave on // ModuleBuilder. //************************************************* internal int PrepareCreateCustomAttributeToDisk(ModuleBuilder mod) { return mod.InternalGetConstructorToken(m_con, true).Token; } //************************************************* // Call this function with toDisk=1, after on disk module has been snapped. //************************************************* internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner, int tkAttrib, bool toDisk) { TypeBuilder.InternalCreateCustomAttribute(tkOwner, tkAttrib, m_blob, mod, toDisk, typeof(System.Diagnostics.DebuggableAttribute) == m_con.DeclaringType); } void _CustomAttributeBuilder.GetTypeInfoCount(out uint pcTInfo) { throw new NotImplementedException(); } void _CustomAttributeBuilder.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo) { throw new NotImplementedException(); } void _CustomAttributeBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId) { throw new NotImplementedException(); } void _CustomAttributeBuilder.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr) { throw new NotImplementedException(); } internal ConstructorInfo m_con; internal Object[] m_constructorArgs; internal byte[] m_blob; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: CustomAttrbuteBuilder ** ** ** CustomAttributeBuilder is a helper class to help building custom attribute. ** ** ===========================================================*/ namespace System.Reflection.Emit { using System; using System.Reflection; using System.Reflection.Emit; using System.IO; using System.Text; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Globalization; [HostProtection(MayLeakOnAbort = true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(_CustomAttributeBuilder))] [System.Runtime.InteropServices.ComVisible(true)] public class CustomAttributeBuilder : _CustomAttributeBuilder { // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs) { InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[]{}, new Object[]{}, new FieldInfo[]{}, new Object[]{}); } // public constructor to form the custom attribute with constructor, constructor // parameters and named properties. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues) { InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, new FieldInfo[]{}, new Object[]{}); } // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, FieldInfo[] namedFields, Object[] fieldValues) { InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[]{}, new Object[]{}, namedFields, fieldValues); } // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues) { InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues); } private const byte SERIALIZATION_TYPE_BOOLEAN = SignatureHelper.ELEMENT_TYPE_BOOLEAN; private const byte SERIALIZATION_TYPE_CHAR = SignatureHelper.ELEMENT_TYPE_CHAR; private const byte SERIALIZATION_TYPE_I1 = SignatureHelper.ELEMENT_TYPE_I1; private const byte SERIALIZATION_TYPE_U1 = SignatureHelper.ELEMENT_TYPE_U1; private const byte SERIALIZATION_TYPE_I2 = SignatureHelper.ELEMENT_TYPE_I2; private const byte SERIALIZATION_TYPE_U2 = SignatureHelper.ELEMENT_TYPE_U2; private const byte SERIALIZATION_TYPE_I4 = SignatureHelper.ELEMENT_TYPE_I4; private const byte SERIALIZATION_TYPE_U4 = SignatureHelper.ELEMENT_TYPE_U4; private const byte SERIALIZATION_TYPE_I8 = SignatureHelper.ELEMENT_TYPE_I8; private const byte SERIALIZATION_TYPE_U8 = SignatureHelper.ELEMENT_TYPE_U8; private const byte SERIALIZATION_TYPE_R4 = SignatureHelper.ELEMENT_TYPE_R4; private const byte SERIALIZATION_TYPE_R8 = SignatureHelper.ELEMENT_TYPE_R8; private const byte SERIALIZATION_TYPE_STRING = SignatureHelper.ELEMENT_TYPE_STRING; private const byte SERIALIZATION_TYPE_SZARRAY = SignatureHelper.ELEMENT_TYPE_SZARRAY; private const byte SERIALIZATION_TYPE_TYPE = 0x50; private const byte SERIALIZATION_TYPE_TAGGED_OBJECT = 0x51; private const byte SERIALIZATION_TYPE_FIELD = 0x53; private const byte SERIALIZATION_TYPE_PROPERTY = 0x54; private const byte SERIALIZATION_TYPE_ENUM = 0x55; // Check that a type is suitable for use in a custom attribute. private bool ValidateType(Type t) { if (t.IsPrimitive || t == typeof(String) || t == typeof(Type)) return true; if (t.IsEnum) { switch (Type.GetTypeCode(Enum.GetUnderlyingType(t))) { case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: return true; default: return false; } } if (t.IsArray) { if (t.GetArrayRank() != 1) return false; return ValidateType(t.GetElementType()); } return t == typeof(Object); } internal void InitCustomAttributeBuilder(ConstructorInfo con, Object[] constructorArgs, PropertyInfo[] namedProperties, Object[] propertyValues, FieldInfo[] namedFields, Object[] fieldValues) { if (con == null) throw new ArgumentNullException("con"); if (constructorArgs == null) throw new ArgumentNullException("constructorArgs"); if (namedProperties == null) throw new ArgumentNullException("constructorArgs"); if (propertyValues == null) throw new ArgumentNullException("propertyValues"); if (namedFields == null) throw new ArgumentNullException("namedFields"); if (fieldValues == null) throw new ArgumentNullException("fieldValues"); if (namedProperties.Length != propertyValues.Length) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedProperties, propertyValues"); if (namedFields.Length != fieldValues.Length) throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedFields, fieldValues"); if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static || (con.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructor")); if ((con.CallingConvention & CallingConventions.Standard) != CallingConventions.Standard) throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructorCallConv")); // Cache information used elsewhere. m_con = con; m_constructorArgs = new Object[constructorArgs.Length]; Array.Copy(constructorArgs, m_constructorArgs, constructorArgs.Length); Type[] paramTypes; int i; // Get the types of the constructor's formal parameters. if (con is ConstructorBuilder) { paramTypes = ((ConstructorBuilder)con).GetParameterTypes(); } else { ParameterInfo[] paramInfos = con.GetParametersNoCopy(); paramTypes = new Type[paramInfos.Length]; for (i = 0; i < paramInfos.Length; i++) paramTypes[i] = paramInfos[i].ParameterType; } // Since we're guaranteed a non-var calling convention, the number of arguments must equal the number of parameters. if (paramTypes.Length != constructorArgs.Length) throw new ArgumentException(Environment.GetResourceString("Argument_BadParameterCountsForConstructor")); // Verify that the constructor has a valid signature (custom attributes only support a subset of our type system). for (i = 0; i < paramTypes.Length; i++) if (!ValidateType(paramTypes[i])) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Now verify that the types of the actual parameters are compatible with the types of the formal parameters. for (i = 0; i < paramTypes.Length; i++) { if (constructorArgs[i] == null) continue; TypeCode paramTC = Type.GetTypeCode(paramTypes[i]); if (paramTC != Type.GetTypeCode(constructorArgs[i].GetType())) if (paramTC != TypeCode.Object || !ValidateType(constructorArgs[i].GetType())) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForConstructor"), i)); } // Allocate a memory stream to represent the CA blob in the metadata and a binary writer to help format it. MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); // Write the blob protocol version (currently 1). writer.Write((ushort)1); // Now emit the constructor argument values (no need for types, they're inferred from the constructor signature). for (i = 0; i < constructorArgs.Length; i++) EmitValue(writer, paramTypes[i], constructorArgs[i]); // Next a short with the count of properties and fields. writer.Write((ushort)(namedProperties.Length + namedFields.Length)); // Emit all the property sets. for (i = 0; i < namedProperties.Length; i++) { // Validate the property. if (namedProperties[i] == null) throw new ArgumentNullException("namedProperties[" + i + "]"); // Allow null for non-primitive types only. Type propType = namedProperties[i].PropertyType; if (propertyValues[i] == null && propType.IsPrimitive) throw new ArgumentNullException("propertyValues[" + i + "]"); // Validate property type. if (!ValidateType(propType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Property has to be writable. if (!namedProperties[i].CanWrite) throw new ArgumentException(Environment.GetResourceString("Argument_NotAWritableProperty")); // Property has to be from the same class or base class as ConstructorInfo. if (namedProperties[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedProperties[i].DeclaringType)) { // Might have failed check because one type is a XXXBuilder // and the other is not. Deal with these special cases // separately. if (!TypeBuilder.IsTypeEqual(namedProperties[i].DeclaringType, con.DeclaringType)) { // IsSubclassOf is overloaded to do the right thing if // the constructor is a TypeBuilder, but we still need // to deal with the case where the property's declaring // type is one. if (!(namedProperties[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedProperties[i].DeclaringType).m_runtimeType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadPropertyForConstructorBuilder")); } } // Make sure the property's type can take the given value. // Note that there will be no coersion. if (propertyValues[i] != null && propType != typeof(Object) && Type.GetTypeCode(propertyValues[i].GetType()) != Type.GetTypeCode(propType)) throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch")); // First a byte indicating that this is a property. writer.Write(SERIALIZATION_TYPE_PROPERTY); // Emit the property type, name and value. EmitType(writer, propType); EmitString(writer, namedProperties[i].Name); EmitValue(writer, propType, propertyValues[i]); } // Emit all the field sets. for (i = 0; i < namedFields.Length; i++) { // Validate the field. if (namedFields[i] == null) throw new ArgumentNullException("namedFields[" + i + "]"); // Allow null for non-primitive types only. Type fldType = namedFields[i].FieldType; if (fieldValues[i] == null && fldType.IsPrimitive) throw new ArgumentNullException("fieldValues[" + i + "]"); // Validate field type. if (!ValidateType(fldType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute")); // Field has to be from the same class or base class as ConstructorInfo. if (namedFields[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedFields[i].DeclaringType)) { // Might have failed check because one type is a XXXBuilder // and the other is not. Deal with these special cases // separately. if (!TypeBuilder.IsTypeEqual(namedFields[i].DeclaringType, con.DeclaringType)) { // IsSubclassOf is overloaded to do the right thing if // the constructor is a TypeBuilder, but we still need // to deal with the case where the field's declaring // type is one. if (!(namedFields[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedFields[i].DeclaringType).m_runtimeType)) throw new ArgumentException(Environment.GetResourceString("Argument_BadFieldForConstructorBuilder")); } } // Make sure the field's type can take the given value. // Note that there will be no coersion. if (fieldValues[i] != null && fldType != typeof(Object) && Type.GetTypeCode(fieldValues[i].GetType()) != Type.GetTypeCode(fldType)) throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch")); // First a byte indicating that this is a field. writer.Write(SERIALIZATION_TYPE_FIELD); // Emit the field type, name and value. EmitType(writer, fldType); EmitString(writer, namedFields[i].Name); EmitValue(writer, fldType, fieldValues[i]); } // Create the blob array. m_blob = ((MemoryStream)writer.BaseStream).ToArray(); } private void EmitType(BinaryWriter writer, Type type) { if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.SByte: writer.Write(SERIALIZATION_TYPE_I1); break; case TypeCode.Byte: writer.Write(SERIALIZATION_TYPE_U1); break; case TypeCode.Char: writer.Write(SERIALIZATION_TYPE_CHAR); break; case TypeCode.Boolean: writer.Write(SERIALIZATION_TYPE_BOOLEAN); break; case TypeCode.Int16: writer.Write(SERIALIZATION_TYPE_I2); break; case TypeCode.UInt16: writer.Write(SERIALIZATION_TYPE_U2); break; case TypeCode.Int32: writer.Write(SERIALIZATION_TYPE_I4); break; case TypeCode.UInt32: writer.Write(SERIALIZATION_TYPE_U4); break; case TypeCode.Int64: writer.Write(SERIALIZATION_TYPE_I8); break; case TypeCode.UInt64: writer.Write(SERIALIZATION_TYPE_U8); break; case TypeCode.Single: writer.Write(SERIALIZATION_TYPE_R4); break; case TypeCode.Double: writer.Write(SERIALIZATION_TYPE_R8); break; default: BCLDebug.Assert(false, "Invalid primitive type"); break; } } else if (type.IsEnum) { writer.Write(SERIALIZATION_TYPE_ENUM); EmitString(writer, type.AssemblyQualifiedName); } else if (type == typeof(String)) { writer.Write(SERIALIZATION_TYPE_STRING); } else if (type == typeof(Type)) { writer.Write(SERIALIZATION_TYPE_TYPE); } else if (type.IsArray) { writer.Write(SERIALIZATION_TYPE_SZARRAY); EmitType(writer, type.GetElementType()); } else { // Tagged object case. writer.Write(SERIALIZATION_TYPE_TAGGED_OBJECT); } } private void EmitString(BinaryWriter writer, String str) { // Strings are emitted with a length prefix in a compressed format (1, 2 or 4 bytes) as used internally by metadata. byte[] utf8Str = Encoding.UTF8.GetBytes(str); uint length = (uint)utf8Str.Length; if (length <= 0x7f) { writer.Write((byte)length); } else if (length <= 0x3fff) { writer.Write((byte)((length >> 8) | 0x80)); writer.Write((byte)(length & 0xff)); } else { writer.Write((byte)((length >> 24) | 0xc0)); writer.Write((byte)((length >> 16) & 0xff)); writer.Write((byte)((length >> 8) & 0xff)); writer.Write((byte)(length & 0xff)); } writer.Write(utf8Str); } private void EmitValue(BinaryWriter writer, Type type, Object value) { if (type.IsEnum) { switch (Type.GetTypeCode(Enum.GetUnderlyingType(type))) { case TypeCode.SByte: writer.Write((sbyte)value); break; case TypeCode.Byte: writer.Write((byte)value); break; case TypeCode.Int16: writer.Write((short)value); break; case TypeCode.UInt16: writer.Write((ushort)value); break; case TypeCode.Int32: writer.Write((int)value); break; case TypeCode.UInt32: writer.Write((uint)value); break; case TypeCode.Int64: writer.Write((long)value); break; case TypeCode.UInt64: writer.Write((ulong)value); break; default: BCLDebug.Assert(false, "Invalid enum base type"); break; } } else if (type == typeof(String)) { if (value == null) writer.Write((byte)0xff); else EmitString(writer, (String)value); } else if (type == typeof(Type)) { if (value == null) writer.Write((byte)0xff); else { String typeName = TypeNameBuilder.ToString((Type)value, TypeNameBuilder.Format.AssemblyQualifiedName); if (typeName == null) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidTypeForCA"), value.GetType())); EmitString(writer, typeName); } } else if (type.IsArray) { if (value == null) writer.Write((uint)0xffffffff); else { Array a = (Array)value; Type et = type.GetElementType(); writer.Write(a.Length); for (int i = 0; i < a.Length; i++) EmitValue(writer, et, a.GetValue(i)); } } else if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.SByte: writer.Write((sbyte)value); break; case TypeCode.Byte: writer.Write((byte)value); break; case TypeCode.Char: writer.Write(Convert.ToInt16((char)value)); break; case TypeCode.Boolean: writer.Write((byte)((bool)value ? 1 : 0)); break; case TypeCode.Int16: writer.Write((short)value); break; case TypeCode.UInt16: writer.Write((ushort)value); break; case TypeCode.Int32: writer.Write((int)value); break; case TypeCode.UInt32: writer.Write((uint)value); break; case TypeCode.Int64: writer.Write((long)value); break; case TypeCode.UInt64: writer.Write((ulong)value); break; case TypeCode.Single: writer.Write((float)value); break; case TypeCode.Double: writer.Write((double)value); break; default: BCLDebug.Assert(false, "Invalid primitive type"); break; } } else if (type == typeof(object)) { // Tagged object case. Type instances aren't actually Type, they're some subclass (such as RuntimeType or // TypeBuilder), so we need to canonicalize this case back to Type. If we have a null value we follow the convention // used by C# and emit a null typed as a string (it doesn't really matter what type we pick as long as it's a // reference type). Type ot = value == null ? typeof(String) : value is Type ? typeof(Type) : value.GetType(); EmitType(writer, ot); EmitValue(writer, ot, value); } else { string typename = "null"; if (value != null) typename = value.GetType().ToString(); throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForCAB"), typename)); } } // return the byte interpretation of the custom attribute internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner) { CreateCustomAttribute(mod, tkOwner, mod.GetConstructorToken(m_con).Token, false); } //************************************************* // Upon saving to disk, we need to create the memberRef token for the custom attribute's type // first of all. So when we snap the in-memory module for on disk, this token will be there. // We also need to enforce the use of MemberRef. Because MemberDef token might move. // This function has to be called before we snap the in-memory module for on disk (i.e. Presave on // ModuleBuilder. //************************************************* internal int PrepareCreateCustomAttributeToDisk(ModuleBuilder mod) { return mod.InternalGetConstructorToken(m_con, true).Token; } //************************************************* // Call this function with toDisk=1, after on disk module has been snapped. //************************************************* internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner, int tkAttrib, bool toDisk) { TypeBuilder.InternalCreateCustomAttribute(tkOwner, tkAttrib, m_blob, mod, toDisk, typeof(System.Diagnostics.DebuggableAttribute) == m_con.DeclaringType); } void _CustomAttributeBuilder.GetTypeInfoCount(out uint pcTInfo) { throw new NotImplementedException(); } void _CustomAttributeBuilder.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo) { throw new NotImplementedException(); } void _CustomAttributeBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId) { throw new NotImplementedException(); } void _CustomAttributeBuilder.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr) { throw new NotImplementedException(); } internal ConstructorInfo m_con; internal Object[] m_constructorArgs; internal byte[] m_blob; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FileSystemInfo.cs
- TileBrush.cs
- Dictionary.cs
- SoapObjectInfo.cs
- TextBlock.cs
- InputLanguageEventArgs.cs
- TemplatedControlDesigner.cs
- FileDialogPermission.cs
- LayoutManager.cs
- RecognizerInfo.cs
- DocumentPageHost.cs
- DbConvert.cs
- SizeAnimationClockResource.cs
- SourceLocationProvider.cs
- Int64AnimationBase.cs
- ClientScriptItem.cs
- CorrelationService.cs
- BaseDataBoundControl.cs
- MarkupWriter.cs
- TimeSpan.cs
- OutputWindow.cs
- LocatorPart.cs
- HttpCachePolicyElement.cs
- CodeGroup.cs
- __FastResourceComparer.cs
- TextElementAutomationPeer.cs
- Normalization.cs
- VirtualDirectoryMapping.cs
- XmlEncodedRawTextWriter.cs
- PropertyBuilder.cs
- LeaseManager.cs
- CursorConverter.cs
- ParallelTimeline.cs
- DurationConverter.cs
- TransformCollection.cs
- LocalValueEnumerator.cs
- XPathCompileException.cs
- InternalSafeNativeMethods.cs
- SupportingTokenChannel.cs
- MouseActionValueSerializer.cs
- BindingContext.cs
- RegexInterpreter.cs
- DoubleLinkList.cs
- MergePropertyDescriptor.cs
- ValidationPropertyAttribute.cs
- XDRSchema.cs
- XmlLinkedNode.cs
- DeviceSpecificDialogCachedState.cs
- QilInvokeEarlyBound.cs
- UxThemeWrapper.cs
- BoundingRectTracker.cs
- HostedElements.cs
- ClearCollection.cs
- XPathNodeHelper.cs
- SessionParameter.cs
- DocumentApplicationDocumentViewer.cs
- UnauthorizedAccessException.cs
- DrawingVisualDrawingContext.cs
- Roles.cs
- Rules.cs
- SimpleExpression.cs
- BamlBinaryReader.cs
- VerticalAlignConverter.cs
- Typeface.cs
- MD5CryptoServiceProvider.cs
- DefaultBindingPropertyAttribute.cs
- ZipIOFileItemStream.cs
- AccessibilityHelperForVista.cs
- ScrollViewerAutomationPeer.cs
- securitycriticaldataformultiplegetandset.cs
- RelationshipEndMember.cs
- SqlMetaData.cs
- SoundPlayer.cs
- AspNetSynchronizationContext.cs
- MergePropertyDescriptor.cs
- SHA512Managed.cs
- XmlParserContext.cs
- ViewBox.cs
- OleDbWrapper.cs
- SqlCacheDependencyDatabase.cs
- InitializerFacet.cs
- OdbcParameterCollection.cs
- ContentTextAutomationPeer.cs
- KeyNotFoundException.cs
- EmptyQuery.cs
- StrokeNodeData.cs
- EventLogSession.cs
- SapiAttributeParser.cs
- Matrix.cs
- PersonalizationDictionary.cs
- DoubleLinkListEnumerator.cs
- LineGeometry.cs
- BitStack.cs
- ListViewGroupConverter.cs
- DBCSCodePageEncoding.cs
- OleDbErrorCollection.cs
- SqlDataAdapter.cs
- InstanceLockTracking.cs
- AppDomainFactory.cs
- DataErrorValidationRule.cs