3 // System.Reflection.Emit/CustomAttributeBuilder.cs
6 // Paolo Molaro (lupus@ximian.com)
8 // (C) 2001 Ximian, Inc. http://www.ximian.com
12 using System.Reflection;
13 using System.Reflection.Emit;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.InteropServices;
17 namespace System.Reflection.Emit {
18 public class CustomAttributeBuilder {
22 internal ConstructorInfo Ctor {
26 internal byte[] Data {
30 [MethodImplAttribute(MethodImplOptions.InternalCall)]
31 static extern byte[] GetBlob(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues);
33 internal CustomAttributeBuilder( ConstructorInfo con, byte[] cdata) {
35 data = (byte[])cdata.Clone ();
36 /* should we check that the user supplied data is correct? */
39 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs)
41 Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
42 new FieldInfo [0], new object [0]);
44 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
45 FieldInfo[] namedFields, object[] fieldValues)
47 Initialize (con, constructorArgs, new PropertyInfo [0], new object [0],
48 namedFields, fieldValues);
50 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
51 PropertyInfo[] namedProperties, object[] propertyValues)
53 Initialize (con, constructorArgs, namedProperties, propertyValues, new FieldInfo [0],
56 public CustomAttributeBuilder( ConstructorInfo con, object[] constructorArgs,
57 PropertyInfo[] namedProperties, object[] propertyValues,
58 FieldInfo[] namedFields, object[] fieldValues)
60 Initialize (con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
63 private void Initialize (ConstructorInfo con, object [] constructorArgs,
64 PropertyInfo [] namedProperties, object [] propertyValues,
65 FieldInfo [] namedFields, object [] fieldValues)
69 throw new ArgumentNullException ("con");
70 if (constructorArgs == null)
71 throw new ArgumentNullException ("constructorArgs");
72 if (namedProperties == null)
73 throw new ArgumentNullException ("namedProperties");
74 if (propertyValues == null)
75 throw new ArgumentNullException ("propertyValues");
76 if (namedFields == null)
77 throw new ArgumentNullException ("namedFields");
78 if (fieldValues == null)
79 throw new ArgumentNullException ("fieldValues");
80 if (con.GetParameterCount () != constructorArgs.Length)
81 throw new ArgumentException ("Parameter count does not match " +
82 "passed in argument value count.");
83 if (namedProperties.Length != propertyValues.Length)
84 throw new ArgumentException ("Array lengths must be the same.",
85 "namedProperties, propertyValues");
86 if (namedFields.Length != fieldValues.Length)
87 throw new ArgumentException ("Array lengths must be the same.",
88 "namedFields, fieldValues");
89 if ((con.Attributes & MethodAttributes.Static) == MethodAttributes.Static ||
90 (con.Attributes & MethodAttributes.Private) == MethodAttributes.Private)
91 throw new ArgumentException ("Cannot have private or static constructor.");
93 Type atype = ctor.DeclaringType;
96 foreach (FieldInfo fi in namedFields) {
97 Type t = fi.DeclaringType;
98 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
99 throw new ArgumentException ("Field '" + fi.Name + "' does not belong to the same class as the constructor");
100 // FIXME: Check enums and TypeBuilders as well
101 if (fieldValues [i] != null)
102 // IsEnum does not seem to work on TypeBuilders
103 if (!(fi.FieldType is TypeBuilder) && !fi.FieldType.IsEnum && !fi.FieldType.IsAssignableFrom (fieldValues [i].GetType ())) {
105 // mcs allways uses object[] for array types and
106 // MS.NET allows this
108 if (!fi.FieldType.IsArray)
109 throw new ArgumentException ("Value of field '" + fi.Name + "' does not match field type: " + fi.FieldType);
115 foreach (PropertyInfo pi in namedProperties) {
117 throw new ArgumentException ("Property '" + pi.Name + "' does not have a setter.");
118 Type t = pi.DeclaringType;
119 if ((atype != t) && (!t.IsSubclassOf (atype)) && (!atype.IsSubclassOf (t)))
120 throw new ArgumentException ("Property '" + pi.Name + "' does not belong to the same class as the constructor");
121 if (propertyValues [i] != null) {
122 if (!(pi.PropertyType is TypeBuilder) && !pi.PropertyType.IsEnum && !pi.PropertyType.IsAssignableFrom (propertyValues [i].GetType ()))
123 if (!pi.PropertyType.IsArray)
124 throw new ArgumentException ("Value of property '" + pi.Name + "' does not match property type: " + pi.PropertyType + " -> " + propertyValues [i]);
130 foreach (ParameterInfo pi in con.GetParameters ()) {
132 Type paramType = pi.ParameterType;
133 if (constructorArgs [i] != null)
134 if (!(paramType is TypeBuilder) && !paramType.IsEnum && !paramType.IsAssignableFrom (constructorArgs [i].GetType ()))
135 if (!paramType.IsArray)
136 throw new ArgumentException ("Value of argument " + i + " does not match parameter type: " + paramType + " -> " + constructorArgs [i]);
141 data = GetBlob (con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
145 internal static int decode_len (byte[] data, int pos, out int rpos) {
147 if ((data [pos] & 0x80) == 0) {
148 len = (int)(data [pos++] & 0x7f);
149 } else if ((data [pos] & 0x40) == 0) {
150 len = ((data [pos] & 0x3f) << 8) + data [pos + 1];
153 len = ((data [pos] & 0x1f) << 24) + (data [pos + 1] << 16) + (data [pos + 2] << 8) + data [pos + 3];
160 internal static string string_from_bytes (byte[] data, int pos, int len)
162 return System.Text.Encoding.UTF8.GetString(data, pos, len);
165 internal string string_arg ()
168 int len = decode_len (data, pos, out pos);
169 return string_from_bytes (data, pos, len);
172 internal static UnmanagedMarshal get_umarshal (CustomAttributeBuilder customBuilder, bool is_field) {
173 byte[] data = customBuilder.Data;
174 UnmanagedType subtype = UnmanagedType.I4;
177 int utype; /* the (stupid) ctor takes a short or an enum ... */
178 utype = (int)data [2];
179 utype |= ((int)data [3]) << 8;
181 string first_type_name = customBuilder.Ctor.GetParameters()[0].ParameterType.FullName;
183 if (first_type_name == "System.Int16")
185 int nnamed = (int)data [pos++];
186 nnamed |= ((int)data [pos++]) << 8;
188 for (int i = 0; i < nnamed; ++i) {
189 int paramType; // What is this ?
190 paramType = (int)data [pos++];
191 paramType |= ((int)data [pos++]) << 8;
192 int len = decode_len (data, pos, out pos);
193 string named_name = string_from_bytes (data, pos, len);
196 switch (named_name) {
198 value = (int)data [pos++];
199 value |= ((int)data [pos++]) << 8;
200 value |= ((int)data [pos++]) << 16;
201 value |= ((int)data [pos++]) << 24;
202 subtype = (UnmanagedType)value;
205 value = (int)data [pos++];
206 value |= ((int)data [pos++]) << 8;
207 value |= ((int)data [pos++]) << 16;
208 value |= ((int)data [pos++]) << 24;
216 switch ((UnmanagedType)utype) {
217 case UnmanagedType.LPArray:
218 return UnmanagedMarshal.DefineLPArray (subtype);
219 case UnmanagedType.SafeArray:
220 return UnmanagedMarshal.DefineSafeArray (subtype);
221 case UnmanagedType.ByValArray:
222 return UnmanagedMarshal.DefineByValArray (sizeConst);
223 case UnmanagedType.ByValTStr:
224 return UnmanagedMarshal.DefineByValTStr (sizeConst);
226 return UnmanagedMarshal.DefineUnmanagedMarshal ((UnmanagedType)utype);