The Labs \ Source Viewer \ SSCLI \ System.Reflection.Emit \ CustomAttributeBuilder

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  CustomAttrbuteBuilder
  18. **
  19. **
  20. ** CustomAttributeBuilder is a helper class to help building custom attribute.
  21. **
  22. **
  23. ===========================================================*/
  24. namespace System.Reflection.Emit
  25. {
  26.    
  27.    
  28.     using System;
  29.     using System.Reflection;
  30.     using System.Reflection.Emit;
  31.     using System.IO;
  32.     using System.Text;
  33.     using System.Security.Permissions;
  34.     using System.Runtime.InteropServices;
  35.     using System.Globalization;
  36.    
  37.     [HostProtection(MayLeakOnAbort = true)]
  38.     [ClassInterface(ClassInterfaceType.None)]
  39.     [ComDefaultInterface(typeof(_CustomAttributeBuilder))]
  40.     [System.Runtime.InteropServices.ComVisible(true)]
  41.     public class CustomAttributeBuilder : _CustomAttributeBuilder
  42.     {
  43.         // public constructor to form the custom attribute with constructor and constructor
  44.         // parameters.
  45.         public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
  46.         {
  47.             InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[] {}, new object[] {}, new FieldInfo[] {}, new object[] {});
  48.         }
  49.        
  50.         // public constructor to form the custom attribute with constructor, constructor
  51.         // parameters and named properties.
  52.         public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues)
  53.         {
  54.             InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, new FieldInfo[] {}, new object[] {});
  55.         }
  56.        
  57.         // public constructor to form the custom attribute with constructor and constructor
  58.         // parameters.
  59.         public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
  60.         {
  61.             InitCustomAttributeBuilder(con, constructorArgs, new PropertyInfo[] {}, new object[] {}, namedFields, fieldValues);
  62.         }
  63.        
  64.         // public constructor to form the custom attribute with constructor and constructor
  65.         // parameters.
  66.         public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
  67.         {
  68.             InitCustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
  69.         }
  70.        
  71.         private const byte SERIALIZATION_TYPE_BOOLEAN = SignatureHelper.ELEMENT_TYPE_BOOLEAN;
  72.         private const byte SERIALIZATION_TYPE_CHAR = SignatureHelper.ELEMENT_TYPE_CHAR;
  73.         private const byte SERIALIZATION_TYPE_I1 = SignatureHelper.ELEMENT_TYPE_I1;
  74.         private const byte SERIALIZATION_TYPE_U1 = SignatureHelper.ELEMENT_TYPE_U1;
  75.         private const byte SERIALIZATION_TYPE_I2 = SignatureHelper.ELEMENT_TYPE_I2;
  76.         private const byte SERIALIZATION_TYPE_U2 = SignatureHelper.ELEMENT_TYPE_U2;
  77.         private const byte SERIALIZATION_TYPE_I4 = SignatureHelper.ELEMENT_TYPE_I4;
  78.         private const byte SERIALIZATION_TYPE_U4 = SignatureHelper.ELEMENT_TYPE_U4;
  79.         private const byte SERIALIZATION_TYPE_I8 = SignatureHelper.ELEMENT_TYPE_I8;
  80.         private const byte SERIALIZATION_TYPE_U8 = SignatureHelper.ELEMENT_TYPE_U8;
  81.         private const byte SERIALIZATION_TYPE_R4 = SignatureHelper.ELEMENT_TYPE_R4;
  82.         private const byte SERIALIZATION_TYPE_R8 = SignatureHelper.ELEMENT_TYPE_R8;
  83.         private const byte SERIALIZATION_TYPE_STRING = SignatureHelper.ELEMENT_TYPE_STRING;
  84.         private const byte SERIALIZATION_TYPE_SZARRAY = SignatureHelper.ELEMENT_TYPE_SZARRAY;
  85.         private const byte SERIALIZATION_TYPE_TYPE = 80;
  86.         private const byte SERIALIZATION_TYPE_TAGGED_OBJECT = 81;
  87.         private const byte SERIALIZATION_TYPE_FIELD = 83;
  88.         private const byte SERIALIZATION_TYPE_PROPERTY = 84;
  89.         private const byte SERIALIZATION_TYPE_ENUM = 85;
  90.        
  91.         // Check that a type is suitable for use in a custom attribute.
  92.         private bool ValidateType(Type t)
  93.         {
  94.             if (t.IsPrimitive || t == typeof(string) || t == typeof(Type))
  95.                 return true;
  96.             if (t.IsEnum) {
  97.                 switch (Type.GetTypeCode(Enum.GetUnderlyingType(t))) {
  98.                     case TypeCode.SByte:
  99.                     case TypeCode.Byte:
  100.                     case TypeCode.Int16:
  101.                     case TypeCode.UInt16:
  102.                     case TypeCode.Int32:
  103.                     case TypeCode.UInt32:
  104.                     case TypeCode.Int64:
  105.                     case TypeCode.UInt64:
  106.                         return true;
  107.                     default:
  108.                         return false;
  109.                 }
  110.             }
  111.             if (t.IsArray) {
  112.                 if (t.GetArrayRank() != 1)
  113.                     return false;
  114.                 return ValidateType(t.GetElementType());
  115.             }
  116.             return t == typeof(object);
  117.         }
  118.        
  119.         internal void InitCustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
  120.         {
  121.             if (con == null)
  122.                 throw new ArgumentNullException("con");
  123.             if (constructorArgs == null)
  124.                 throw new ArgumentNullException("constructorArgs");
  125.             if (namedProperties == null)
  126.                 throw new ArgumentNullException("constructorArgs");
  127.             if (propertyValues == null)
  128.                 throw new ArgumentNullException("propertyValues");
  129.             if (namedFields == null)
  130.                 throw new ArgumentNullException("namedFields");
  131.             if (fieldValues == null)
  132.                 throw new ArgumentNullException("fieldValues");
  133.             if (namedProperties.Length != propertyValues.Length)
  134.                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedProperties, propertyValues");
  135.             if (namedFields.Length != fieldValues.Length)
  136.                 throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"), "namedFields, fieldValues");
  137.            
  138.             if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static || (con.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
  139.                 throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructor"));
  140.            
  141.             if ((con.CallingConvention & CallingConventions.Standard) != CallingConventions.Standard)
  142.                 throw new ArgumentException(Environment.GetResourceString("Argument_BadConstructorCallConv"));
  143.            
  144.             // Cache information used elsewhere.
  145.             m_con = con;
  146.             m_constructorArgs = new object[constructorArgs.Length];
  147.             Array.Copy(constructorArgs, m_constructorArgs, constructorArgs.Length);
  148.            
  149.             Type[] paramTypes;
  150.             int i;
  151.            
  152.             // Get the types of the constructor's formal parameters.
  153.             if (con is ConstructorBuilder) {
  154.                 paramTypes = ((ConstructorBuilder)con).GetParameterTypes();
  155.             }
  156.             else {
  157.                 ParameterInfo[] paramInfos = con.GetParametersNoCopy();
  158.                 paramTypes = new Type[paramInfos.Length];
  159.                 for (i = 0; i < paramInfos.Length; i++)
  160.                     paramTypes[i] = paramInfos[i].ParameterType;
  161.             }
  162.            
  163.             // Since we're guaranteed a non-var calling convention, the number of arguments must equal the number of parameters.
  164.             if (paramTypes.Length != constructorArgs.Length)
  165.                 throw new ArgumentException(Environment.GetResourceString("Argument_BadParameterCountsForConstructor"));
  166.            
  167.             // Verify that the constructor has a valid signature (custom attributes only support a subset of our type system).
  168.             for (i = 0; i < paramTypes.Length; i++)
  169.                 if (!ValidateType(paramTypes[i]))
  170.                     throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute"));
  171.            
  172.             // Now verify that the types of the actual parameters are compatible with the types of the formal parameters.
  173.             for (i = 0; i < paramTypes.Length; i++) {
  174.                 if (constructorArgs[i] == null)
  175.                     continue;
  176.                 TypeCode paramTC = Type.GetTypeCode(paramTypes[i]);
  177.                 if (paramTC != Type.GetTypeCode(constructorArgs[i].GetType()))
  178.                     if (paramTC != TypeCode.Object || !ValidateType(constructorArgs[i].GetType()))
  179.                         throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForConstructor"), i));
  180.             }
  181.            
  182.             // Allocate a memory stream to represent the CA blob in the metadata and a binary writer to help format it.
  183.             MemoryStream stream = new MemoryStream();
  184.             BinaryWriter writer = new BinaryWriter(stream);
  185.            
  186.             // Write the blob protocol version (currently 1).
  187.             writer.Write((ushort)1);
  188.            
  189.             // Now emit the constructor argument values (no need for types, they're inferred from the constructor signature).
  190.             for (i = 0; i < constructorArgs.Length; i++)
  191.                 EmitValue(writer, paramTypes[i], constructorArgs[i]);
  192.            
  193.             // Next a short with the count of properties and fields.
  194.             writer.Write((ushort)(namedProperties.Length + namedFields.Length));
  195.            
  196.             // Emit all the property sets.
  197.             for (i = 0; i < namedProperties.Length; i++) {
  198.                 // Validate the property.
  199.                 if (namedProperties[i] == null)
  200.                     throw new ArgumentNullException("namedProperties[" + i + "]");
  201.                
  202.                 // Allow null for non-primitive types only.
  203.                 Type propType = namedProperties[i].PropertyType;
  204.                 if (propertyValues[i] == null && propType.IsPrimitive)
  205.                     throw new ArgumentNullException("propertyValues[" + i + "]");
  206.                
  207.                 // Validate property type.
  208.                 if (!ValidateType(propType))
  209.                     throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute"));
  210.                
  211.                 // Property has to be writable.
  212.                 if (!namedProperties[i].CanWrite)
  213.                     throw new ArgumentException(Environment.GetResourceString("Argument_NotAWritableProperty"));
  214.                
  215.                 // Property has to be from the same class or base class as ConstructorInfo.
  216.                 if (namedProperties[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedProperties[i].DeclaringType)) {
  217.                     // Might have failed check because one type is a XXXBuilder
  218.                     // and the other is not. Deal with these special cases
  219.                     // separately.
  220.                     if (!TypeBuilder.IsTypeEqual(namedProperties[i].DeclaringType, con.DeclaringType)) {
  221.                         // IsSubclassOf is overloaded to do the right thing if
  222.                         // the constructor is a TypeBuilder, but we still need
  223.                         // to deal with the case where the property's declaring
  224.                         // type is one.
  225.                         if (!(namedProperties[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedProperties[i].DeclaringType).m_runtimeType))
  226.                             throw new ArgumentException(Environment.GetResourceString("Argument_BadPropertyForConstructorBuilder"));
  227.                     }
  228.                 }
  229.                
  230.                 // Make sure the property's type can take the given value.
  231.                 // Note that there will be no coersion.
  232.                 if (propertyValues[i] != null && propType != typeof(object) && Type.GetTypeCode(propertyValues[i].GetType()) != Type.GetTypeCode(propType))
  233.                     throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch"));
  234.                
  235.                 // First a byte indicating that this is a property.
  236.                 writer.Write(SERIALIZATION_TYPE_PROPERTY);
  237.                
  238.                 // Emit the property type, name and value.
  239.                 EmitType(writer, propType);
  240.                 EmitString(writer, namedProperties[i].Name);
  241.                 EmitValue(writer, propType, propertyValues[i]);
  242.             }
  243.            
  244.             // Emit all the field sets.
  245.             for (i = 0; i < namedFields.Length; i++) {
  246.                 // Validate the field.
  247.                 if (namedFields[i] == null)
  248.                     throw new ArgumentNullException("namedFields[" + i + "]");
  249.                
  250.                 // Allow null for non-primitive types only.
  251.                 Type fldType = namedFields[i].FieldType;
  252.                 if (fieldValues[i] == null && fldType.IsPrimitive)
  253.                     throw new ArgumentNullException("fieldValues[" + i + "]");
  254.                
  255.                 // Validate field type.
  256.                 if (!ValidateType(fldType))
  257.                     throw new ArgumentException(Environment.GetResourceString("Argument_BadTypeInCustomAttribute"));
  258.                
  259.                 // Field has to be from the same class or base class as ConstructorInfo.
  260.                 if (namedFields[i].DeclaringType != con.DeclaringType && (!(con.DeclaringType is TypeBuilderInstantiation)) && !con.DeclaringType.IsSubclassOf(namedFields[i].DeclaringType)) {
  261.                     // Might have failed check because one type is a XXXBuilder
  262.                     // and the other is not. Deal with these special cases
  263.                     // separately.
  264.                     if (!TypeBuilder.IsTypeEqual(namedFields[i].DeclaringType, con.DeclaringType)) {
  265.                         // IsSubclassOf is overloaded to do the right thing if
  266.                         // the constructor is a TypeBuilder, but we still need
  267.                         // to deal with the case where the field's declaring
  268.                         // type is one.
  269.                         if (!(namedFields[i].DeclaringType is TypeBuilder) || !con.DeclaringType.IsSubclassOf(((TypeBuilder)namedFields[i].DeclaringType).m_runtimeType))
  270.                             throw new ArgumentException(Environment.GetResourceString("Argument_BadFieldForConstructorBuilder"));
  271.                     }
  272.                 }
  273.                
  274.                 // Make sure the field's type can take the given value.
  275.                 // Note that there will be no coersion.
  276.                 if (fieldValues[i] != null && fldType != typeof(object) && Type.GetTypeCode(fieldValues[i].GetType()) != Type.GetTypeCode(fldType))
  277.                     throw new ArgumentException(Environment.GetResourceString("Argument_ConstantDoesntMatch"));
  278.                
  279.                 // First a byte indicating that this is a field.
  280.                 writer.Write(SERIALIZATION_TYPE_FIELD);
  281.                
  282.                 // Emit the field type, name and value.
  283.                 EmitType(writer, fldType);
  284.                 EmitString(writer, namedFields[i].Name);
  285.                 EmitValue(writer, fldType, fieldValues[i]);
  286.             }
  287.            
  288.             // Create the blob array.
  289.             m_blob = ((MemoryStream)writer.BaseStream).ToArray();
  290.         }
  291.        
  292.         private void EmitType(BinaryWriter writer, Type type)
  293.         {
  294.             if (type.IsPrimitive) {
  295.                 switch (Type.GetTypeCode(type)) {
  296.                     case TypeCode.SByte:
  297.                         writer.Write(SERIALIZATION_TYPE_I1);
  298.                         break;
  299.                     case TypeCode.Byte:
  300.                         writer.Write(SERIALIZATION_TYPE_U1);
  301.                         break;
  302.                     case TypeCode.Char:
  303.                         writer.Write(SERIALIZATION_TYPE_CHAR);
  304.                         break;
  305.                     case TypeCode.Boolean:
  306.                         writer.Write(SERIALIZATION_TYPE_BOOLEAN);
  307.                         break;
  308.                     case TypeCode.Int16:
  309.                         writer.Write(SERIALIZATION_TYPE_I2);
  310.                         break;
  311.                     case TypeCode.UInt16:
  312.                         writer.Write(SERIALIZATION_TYPE_U2);
  313.                         break;
  314.                     case TypeCode.Int32:
  315.                         writer.Write(SERIALIZATION_TYPE_I4);
  316.                         break;
  317.                     case TypeCode.UInt32:
  318.                         writer.Write(SERIALIZATION_TYPE_U4);
  319.                         break;
  320.                     case TypeCode.Int64:
  321.                         writer.Write(SERIALIZATION_TYPE_I8);
  322.                         break;
  323.                     case TypeCode.UInt64:
  324.                         writer.Write(SERIALIZATION_TYPE_U8);
  325.                         break;
  326.                     case TypeCode.Single:
  327.                         writer.Write(SERIALIZATION_TYPE_R4);
  328.                         break;
  329.                     case TypeCode.Double:
  330.                         writer.Write(SERIALIZATION_TYPE_R8);
  331.                         break;
  332.                     default:
  333.                         BCLDebug.Assert(false, "Invalid primitive type");
  334.                         break;
  335.                 }
  336.             }
  337.             else if (type.IsEnum) {
  338.                 writer.Write(SERIALIZATION_TYPE_ENUM);
  339.                 EmitString(writer, type.AssemblyQualifiedName);
  340.             }
  341.             else if (type == typeof(string)) {
  342.                 writer.Write(SERIALIZATION_TYPE_STRING);
  343.             }
  344.             else if (type == typeof(Type)) {
  345.                 writer.Write(SERIALIZATION_TYPE_TYPE);
  346.             }
  347.             else if (type.IsArray) {
  348.                 writer.Write(SERIALIZATION_TYPE_SZARRAY);
  349.                 EmitType(writer, type.GetElementType());
  350.             }
  351.             else {
  352.                 // Tagged object case.
  353.                 writer.Write(SERIALIZATION_TYPE_TAGGED_OBJECT);
  354.             }
  355.         }
  356.        
  357.         private void EmitString(BinaryWriter writer, string str)
  358.         {
  359.             // Strings are emitted with a length prefix in a compressed format (1, 2 or 4 bytes) as used internally by metadata.
  360.             byte[] utf8Str = Encoding.UTF8.GetBytes(str);
  361.             uint length = (uint)utf8Str.Length;
  362.             if (length <= 127) {
  363.                 writer.Write((byte)length);
  364.             }
  365.             else if (length <= 16383) {
  366.                 writer.Write((byte)((length >> 8) | 128));
  367.                 writer.Write((byte)(length & 255));
  368.             }
  369.             else {
  370.                 writer.Write((byte)((length >> 24) | 192));
  371.                 writer.Write((byte)((length >> 16) & 255));
  372.                 writer.Write((byte)((length >> 8) & 255));
  373.                 writer.Write((byte)(length & 255));
  374.             }
  375.             writer.Write(utf8Str);
  376.         }
  377.        
  378.         private void EmitValue(BinaryWriter writer, Type type, object value)
  379.         {
  380.             if (type.IsEnum) {
  381.                 switch (Type.GetTypeCode(Enum.GetUnderlyingType(type))) {
  382.                     case TypeCode.SByte:
  383.                         writer.Write((sbyte)value);
  384.                         break;
  385.                     case TypeCode.Byte:
  386.                         writer.Write((byte)value);
  387.                         break;
  388.                     case TypeCode.Int16:
  389.                         writer.Write((short)value);
  390.                         break;
  391.                     case TypeCode.UInt16:
  392.                         writer.Write((ushort)value);
  393.                         break;
  394.                     case TypeCode.Int32:
  395.                         writer.Write((int)value);
  396.                         break;
  397.                     case TypeCode.UInt32:
  398.                         writer.Write((uint)value);
  399.                         break;
  400.                     case TypeCode.Int64:
  401.                         writer.Write((long)value);
  402.                         break;
  403.                     case TypeCode.UInt64:
  404.                         writer.Write((ulong)value);
  405.                         break;
  406.                     default:
  407.                         BCLDebug.Assert(false, "Invalid enum base type");
  408.                         break;
  409.                 }
  410.             }
  411.             else if (type == typeof(string)) {
  412.                 if (value == null)
  413.                     writer.Write((byte)255);
  414.                 else
  415.                     EmitString(writer, (string)value);
  416.             }
  417.             else if (type == typeof(Type)) {
  418.                 if (value == null)
  419.                     writer.Write((byte)255);
  420.                 else {
  421.                     string typeName = TypeNameBuilder.ToString((Type)value, TypeNameBuilder.Format.AssemblyQualifiedName);
  422.                     if (typeName == null)
  423.                         throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidTypeForCA"), value.GetType()));
  424.                     EmitString(writer, typeName);
  425.                 }
  426.             }
  427.             else if (type.IsArray) {
  428.                 if (value == null)
  429.                     writer.Write((uint)4294967295u);
  430.                 else {
  431.                     Array a = (Array)value;
  432.                     Type et = type.GetElementType();
  433.                     writer.Write(a.Length);
  434.                     for (int i = 0; i < a.Length; i++)
  435.                         EmitValue(writer, et, a.GetValue(i));
  436.                 }
  437.             }
  438.             else if (type.IsPrimitive) {
  439.                 switch (Type.GetTypeCode(type)) {
  440.                     case TypeCode.SByte:
  441.                         writer.Write((sbyte)value);
  442.                         break;
  443.                     case TypeCode.Byte:
  444.                         writer.Write((byte)value);
  445.                         break;
  446.                     case TypeCode.Char:
  447.                         writer.Write(Convert.ToInt16((char)value));
  448.                         break;
  449.                     case TypeCode.Boolean:
  450.                         writer.Write((byte)((bool)value ? 1 : 0));
  451.                         break;
  452.                     case TypeCode.Int16:
  453.                         writer.Write((short)value);
  454.                         break;
  455.                     case TypeCode.UInt16:
  456.                         writer.Write((ushort)value);
  457.                         break;
  458.                     case TypeCode.Int32:
  459.                         writer.Write((int)value);
  460.                         break;
  461.                     case TypeCode.UInt32:
  462.                         writer.Write((uint)value);
  463.                         break;
  464.                     case TypeCode.Int64:
  465.                         writer.Write((long)value);
  466.                         break;
  467.                     case TypeCode.UInt64:
  468.                         writer.Write((ulong)value);
  469.                         break;
  470.                     case TypeCode.Single:
  471.                         writer.Write((float)value);
  472.                         break;
  473.                     case TypeCode.Double:
  474.                         writer.Write((double)value);
  475.                         break;
  476.                     default:
  477.                         BCLDebug.Assert(false, "Invalid primitive type");
  478.                         break;
  479.                 }
  480.             }
  481.             else if (type == typeof(object)) {
  482.                 // Tagged object case. Type instances aren't actually Type, they're some subclass (such as RuntimeType or
  483.                 // TypeBuilder), so we need to canonicalize this case back to Type. If we have a null value we follow the convention
  484.                 // 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
  485.                 // reference type).
  486.                 Type ot = value == null ? typeof(string) : value is Type ? typeof(Type) : value.GetType();
  487.                 EmitType(writer, ot);
  488.                 EmitValue(writer, ot, value);
  489.             }
  490.             else {
  491.                 string typename = "null";
  492.                
  493.                 if (value != null)
  494.                     typename = value.GetType().ToString();
  495.                
  496.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_BadParameterTypeForCAB"), typename));
  497.             }
  498.         }
  499.        
  500.        
  501.        
  502.        
  503.         // return the byte interpretation of the custom attribute
  504.         internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner)
  505.         {
  506.             CreateCustomAttribute(mod, tkOwner, mod.GetConstructorToken(m_con).Token, false);
  507.         }
  508.        
  509.         //*************************************************
  510.         // Upon saving to disk, we need to create the memberRef token for the custom attribute's type
  511.         // first of all. So when we snap the in-memory module for on disk, this token will be there.
  512.         // We also need to enforce the use of MemberRef. Because MemberDef token might move.
  513.         // This function has to be called before we snap the in-memory module for on disk (i.e. Presave on
  514.         // ModuleBuilder.
  515.         //*************************************************
  516.         internal int PrepareCreateCustomAttributeToDisk(ModuleBuilder mod)
  517.         {
  518.             return mod.InternalGetConstructorToken(m_con, true).Token;
  519.         }
  520.        
  521.         //*************************************************
  522.         // Call this function with toDisk=1, after on disk module has been snapped.
  523.         //*************************************************
  524.         internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner, int tkAttrib, bool toDisk)
  525.         {
  526.             TypeBuilder.InternalCreateCustomAttribute(tkOwner, tkAttrib, m_blob, mod, toDisk, typeof(System.Diagnostics.DebuggableAttribute) == m_con.DeclaringType);
  527.         }
  528.        
  529.         void _CustomAttributeBuilder.GetTypeInfoCount(out uint pcTInfo)
  530.         {
  531.             throw new NotImplementedException();
  532.         }
  533.        
  534.         void _CustomAttributeBuilder.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
  535.         {
  536.             throw new NotImplementedException();
  537.         }
  538.        
  539.         void _CustomAttributeBuilder.GetIDsOfNames(        [In()]
  540. ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
  541.         {
  542.             throw new NotImplementedException();
  543.         }
  544.        
  545.         void _CustomAttributeBuilder.Invoke(uint dispIdMember,         [In()]
  546. ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
  547.         {
  548.             throw new NotImplementedException();
  549.         }
  550.        
  551.         internal ConstructorInfo m_con;
  552.         internal object[] m_constructorArgs;
  553.         internal byte[] m_blob;
  554.     }
  555. }

Developer Fusion