1 // System.MonoCustomAttrs.cs
2 // Hooks into the runtime to get custom attributes for reflection handles
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
12 using System.Reflection;
13 using System.Collections;
14 using System.Runtime.CompilerServices;
18 internal class MonoCustomAttrs
20 [MethodImplAttribute (MethodImplOptions.InternalCall)]
21 internal static extern object[] GetCustomAttributes (ICustomAttributeProvider obj);
23 internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
27 object[] res = GetCustomAttributes (obj, attributeType, inherit);
32 else if (res.Length > 1)
34 string msg = "'{0}' has more than one attribute of type '{1}";
35 msg = String.Format (msg, obj, attributeType);
36 throw new AmbiguousMatchException (msg);
39 return (Attribute) res[0];
42 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
45 throw new ArgumentNullException ("obj");
48 object[] res = GetCustomAttributes (obj);
50 if (!inherit && res.Length == 1)
52 if (attributeType != null)
54 if (attributeType.IsAssignableFrom (res[0].GetType ()))
56 r = (object[]) Array.CreateInstance (attributeType, 1);
61 r = (object[]) Array.CreateInstance (attributeType, 0);
66 r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
72 // if AttributeType is sealed, and Inherited is set to false, then
73 // there's no use in scanning base types
74 if ((attributeType != null && attributeType.IsSealed) && !inherit)
76 AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
78 if (!usageAttribute.Inherited)
84 int initialSize = res.Length < 16 ? res.Length : 16;
86 Hashtable attributeInfos = new Hashtable (initialSize);
87 ArrayList a = new ArrayList (initialSize);
88 ICustomAttributeProvider btype = obj;
90 int inheritanceLevel = 0;
94 foreach (object attr in res)
96 AttributeUsageAttribute usage;
98 Type attrType = attr.GetType ();
99 if (attributeType != null)
101 if (!attributeType.IsAssignableFrom (attrType))
107 AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
108 if (firstAttribute != null)
110 usage = firstAttribute.Usage;
114 usage = RetrieveAttributeUsage (attrType);
117 // only add attribute to the list of attributes if
118 // - we are on the first inheritance level, or the attribute can be inherited anyway
120 // - multiple attributes of the type are allowed
122 // - this is the first attribute we've discovered
124 // - the attribute is on same inheritance level than the first
125 // attribute that was discovered for this attribute type ))
126 if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
127 (firstAttribute == null || (firstAttribute != null
128 && firstAttribute.InheritanceLevel == inheritanceLevel))))
133 if (firstAttribute == null)
135 attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
139 if ((btype = GetBase (btype)) != null)
142 res = GetCustomAttributes (btype);
144 } while (inherit && btype != null);
146 object[] array = null;
147 if (attributeType == null || attributeType.IsValueType)
149 array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
153 array = Array.CreateInstance (attributeType, a.Count) as object[];
156 // copy attributes to array
162 internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, bool inherit)
165 throw new ArgumentNullException ("obj");
168 return (object[]) GetCustomAttributes (obj).Clone ();
170 return GetCustomAttributes (obj, null, inherit);
173 internal static bool IsDefined (ICustomAttributeProvider obj, Type attributeType, bool inherit)
175 object[] res = GetCustomAttributes (obj);
176 foreach (object attr in res)
178 if (attributeType.Equals (attr.GetType ()))
182 ICustomAttributeProvider btype = GetBase (obj);
183 if (inherit && (btype != null))
184 return IsDefined (btype, attributeType, inherit);
189 // Handles Type, MonoProperty and MonoMethod.
190 // The runtime has also cases for MonoEvent, MonoField, Assembly and ParameterInfo,
191 // but for those we return null here.
192 static ICustomAttributeProvider GetBase (ICustomAttributeProvider obj)
198 return ((Type) obj).BaseType;
200 MethodInfo method = null;
201 if (obj is MonoProperty)
203 MonoProperty prop = (MonoProperty) obj;
204 method = prop.GetGetMethod (true);
206 method = prop.GetSetMethod (true);
208 else if (obj is MonoMethod)
210 method = (MethodInfo) obj;
214 * ParameterInfo -> null
219 if (method == null || !method.IsVirtual)
222 MethodInfo baseMethod = method.GetBaseDefinition ();
223 if (baseMethod == method)
229 private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
231 AttributeUsageAttribute usageAttribute = null;
232 object[] attribs = GetCustomAttributes (attributeType,
233 MonoCustomAttrs.AttributeUsageType, false);
234 if (attribs.Length == 0)
236 // if no AttributeUsage was defined on the attribute level, then
237 // try to retrieve if from its base type
238 if (attributeType.BaseType != null)
240 usageAttribute = RetrieveAttributeUsage (attributeType.BaseType);
243 if (usageAttribute != null)
245 // return AttributeUsage of base class
246 return usageAttribute;
249 // return default AttributeUsageAttribute if no AttributeUsage
250 // was defined on attribute, or its base class
251 return DefaultAttributeUsage;
253 // check if more than one AttributeUsageAttribute has been specified
255 // NOTE: compilers should prevent this, but that doesn't prevent
256 // anyone from using IL ofcourse
257 if (attribs.Length > 1)
259 throw new FormatException ("Duplicate AttributeUsageAttribute cannot be specified on an attribute type.");
262 return ((AttributeUsageAttribute) attribs[0]);
265 private static readonly Type AttributeUsageType = typeof(AttributeUsageAttribute);
266 private static readonly AttributeUsageAttribute DefaultAttributeUsage =
267 new AttributeUsageAttribute (AttributeTargets.All);
269 private class AttributeInfo
271 private AttributeUsageAttribute _usage;
272 private int _inheritanceLevel;
274 public AttributeInfo (AttributeUsageAttribute usage, int inheritanceLevel)
277 _inheritanceLevel = inheritanceLevel;
280 public AttributeUsageAttribute Usage
288 public int InheritanceLevel
292 return _inheritanceLevel;