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();
        }
Example #2
0
        [System.Security.SecuritySafeCritical]  // auto-generated
        private CustomAttributeData(RuntimeModule scope, CustomAttributeRecord caRecord)
        {
            m_scope = scope;
            m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caRecord.tkCtor);

            ParameterInfo[] parameters = m_ctor.GetParametersNoCopy();            
            m_ctorParams = new CustomAttributeCtorParameter[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
                m_ctorParams[i] = new CustomAttributeCtorParameter(InitCustomAttributeType((RuntimeType)parameters[i].ParameterType));

            FieldInfo[] fields = m_ctor.DeclaringType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            PropertyInfo[] properties = m_ctor.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            m_namedParams = new CustomAttributeNamedParameter[properties.Length + fields.Length];
            for (int i = 0; i < fields.Length; i++)
                m_namedParams[i] = new CustomAttributeNamedParameter(
                    fields[i].Name, CustomAttributeEncoding.Field, InitCustomAttributeType((RuntimeType)fields[i].FieldType));
            for (int i = 0; i < properties.Length; i++)
                m_namedParams[i + fields.Length] = new CustomAttributeNamedParameter(
                    properties[i].Name, CustomAttributeEncoding.Property, InitCustomAttributeType((RuntimeType)properties[i].PropertyType));

            m_members = new MemberInfo[fields.Length + properties.Length];
            fields.CopyTo(m_members, 0);
            properties.CopyTo(m_members, fields.Length);

            CustomAttributeEncodedArgument.ParseAttributeArguments(caRecord.blob, ref m_ctorParams, ref m_namedParams, m_scope);
        }